1use pine_builtin_macro::BuiltinFunction;
2use pine_core::{
3 AlertConditionOutput, BoxOutput, DrawingOutput, FillOutput, GlobalOutput, InputOutput,
4 LabelOutput, LineOutput, LogOutput, MetadataOutput, PineOutput, PlotOutput, TableOutput,
5};
6use pine_core::{PineVersion, SymInfo, Timeframe};
7use pine_interpreter::{Builtin, Interpreter, RuntimeError, Value};
8use std::collections::HashMap;
9use std::rc::Rc;
10
11pub use pine_core::Bar;
13pub use pine_core::DefaultPineOutput;
14pub use pine_core::LogLevel;
15pub use pine_interpreter::BuiltinFn;
16pub use pine_interpreter::EvaluatedArg;
17
18mod alertcondition;
20mod array;
21mod barstate;
22mod r#box;
23mod chart;
24mod color;
25mod constants;
26mod currency;
27mod dividends;
28mod earnings;
29mod fill;
30mod footprint;
31mod globals;
32mod indicator;
33mod input;
34mod label;
35mod library;
36mod line;
37mod linefill;
38mod log;
39mod map;
40mod math;
41mod matrix;
42mod plot;
43mod polyline;
44mod request;
45mod runtime;
46mod session;
47mod str;
48mod strategy;
49mod syminfo;
50mod ta;
51mod table;
52mod ticker;
53mod time;
54mod timeframe;
55
56#[derive(BuiltinFunction)]
60#[builtin(name = "na")]
61struct Na<O: PineOutput> {
62 value: Value<O>,
63}
64
65impl<O: PineOutput> Na<O> {
66 fn execute(&self, _ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
67 Ok(Value::Bool(matches!(self.value, Value::Na)))
68 }
69}
70
71#[derive(BuiltinFunction)]
73#[builtin(name = "bool")]
74struct Bool<O: PineOutput> {
75 x: Value<O>,
76}
77
78impl<O: PineOutput> Bool<O> {
79 fn execute(&self, _ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
80 match &self.x {
81 Value::Bool(b) => Ok(Value::Bool(*b)),
82 Value::Int(n) => Ok(Value::Bool(*n != 0)),
83 Value::Number(n) => Ok(Value::Bool(*n != 0.0)),
84 Value::Na => Ok(Value::Bool(false)),
85 _ => Ok(Value::Bool(true)),
86 }
87 }
88}
89
90#[derive(BuiltinFunction)]
92#[builtin(name = "int")]
93struct Int<O: PineOutput> {
94 x: Value<O>,
95}
96
97impl<O: PineOutput> Int<O> {
98 fn execute(&self, _ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
99 match &self.x {
100 Value::Int(n) => Ok(Value::Int(*n)),
101 Value::Number(n) => Ok(Value::Int(n.trunc() as i64)),
102 Value::Bool(b) => Ok(Value::Int(if *b { 1 } else { 0 })),
103 Value::Na => Ok(Value::Na),
104 _ => Err(RuntimeError::TypeError(format!(
105 "Cannot convert {:?} to int",
106 self.x
107 ))),
108 }
109 }
110}
111
112#[derive(BuiltinFunction)]
114#[builtin(name = "float")]
115struct Float<O: PineOutput> {
116 x: Value<O>,
117}
118
119impl<O: PineOutput> Float<O> {
120 fn execute(&self, _ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
121 match &self.x {
122 Value::Int(n) => Ok(Value::Number(*n as f64)),
123 Value::Number(n) => Ok(Value::Number(*n)),
124 Value::Bool(b) => Ok(Value::Number(if *b { 1.0 } else { 0.0 })),
125 Value::Na => Ok(Value::Na),
126 _ => Err(RuntimeError::TypeError(format!(
127 "Cannot convert {:?} to float",
128 self.x
129 ))),
130 }
131 }
132}
133
134#[derive(BuiltinFunction)]
136#[builtin(name = "nz")]
137struct Nz<O: PineOutput> {
138 source: Value<O>,
139 #[arg(default = Value::Number(0.0))]
140 replacement: Value<O>,
141}
142
143impl<O: PineOutput> Nz<O> {
144 fn execute(&self, _ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
145 match &self.source {
148 Value::Na => Ok(self.replacement.clone()),
149 Value::Number(n) if n.is_nan() => Ok(self.replacement.clone()),
150 _ => Ok(self.source.clone()),
151 }
152 }
153}
154
155#[derive(BuiltinFunction)]
157#[builtin(name = "fixnan")]
158struct Fixnan<O: PineOutput> {
159 source: Value<O>,
160}
161
162impl<O: PineOutput> Fixnan<O> {
163 fn execute(&self, _ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
164 match &self.source {
167 Value::Na => {
168 Ok(Value::Number(0.0))
171 }
172 Value::Number(n) if n.is_nan() => Ok(Value::Number(0.0)),
173 _ => Ok(self.source.clone()),
174 }
175 }
176}
177
178fn na_cast<O: PineOutput>() -> BuiltinFn<O> {
181 Rc::new(|_ctx, call_args| {
182 Ok(match call_args.args.into_iter().next() {
183 Some(EvaluatedArg::Positional(v)) => v,
184 Some(EvaluatedArg::Named { value, .. }) => value,
185 None => Value::Na,
186 })
187 })
188}
189
190fn callable_namespace<O: PineOutput>(namespace: Value<O>) -> Value<O> {
193 match namespace {
194 Value::Object {
195 type_name,
196 fields,
197 value,
198 ..
199 } => Value::Object {
200 type_name,
201 fields,
202 value,
203 call: Some(Builtin::untyped(na_cast::<O>())),
204 },
205 other => other,
206 }
207}
208
209pub fn register_namespace_objects<
217 O: PineOutput
218 + LogOutput
219 + PlotOutput
220 + LabelOutput
221 + BoxOutput
222 + InputOutput
223 + LineOutput
224 + TableOutput
225 + MetadataOutput
226 + GlobalOutput
227 + AlertConditionOutput
228 + FillOutput
229 + DrawingOutput,
230>(
231 version: PineVersion,
232 syminfo: Option<SymInfo>,
233 timeframe: Option<Timeframe>,
234) -> (
235 HashMap<String, Value<O>>,
236 Vec<pine_interpreter::PerBarAdvance<O>>,
237) {
238 let mut namespaces = HashMap::new();
239 let mut advances = Vec::new();
240
241 namespaces.insert(
244 "syminfo".to_string(),
245 syminfo::create_syminfo(syminfo.unwrap_or_default()),
246 );
247 namespaces.insert(
248 "timeframe".to_string(),
249 timeframe::register(timeframe.unwrap_or_default()),
250 );
251
252 namespaces.insert("array".to_string(), array::register());
254 namespaces.insert("box".to_string(), callable_namespace(r#box::register()));
255 namespaces.insert("chart".to_string(), chart::register());
256 namespaces.insert("color".to_string(), callable_namespace(color::register()));
257 namespaces.insert("map".to_string(), map::register());
258 namespaces.insert("session".to_string(), session::register());
259 namespaces.insert("runtime".to_string(), runtime::register());
260 namespaces.insert("alert".to_string(), alertcondition::register_alert());
261 namespaces.insert("ticker".to_string(), ticker::register());
262 namespaces.insert("earnings".to_string(), earnings::register());
263 namespaces.insert("footprint".to_string(), footprint::register_footprint());
264 namespaces.insert("volume_row".to_string(), footprint::register_volume_row());
265 namespaces.insert("dividends".to_string(), dividends::register());
266 namespaces.insert("currency".to_string(), currency::register());
267 for (name, value) in input::register(version) {
268 namespaces.insert(name, value);
269 }
270 namespaces.insert("label".to_string(), callable_namespace(label::register()));
271 for (name, value) in line::register(version) {
272 let value = if name == "line" {
274 callable_namespace(value)
275 } else {
276 value
277 };
278 namespaces.insert(name, value);
279 }
280 namespaces.insert(
281 "string".to_string(),
282 Value::BuiltinFunction(Builtin::untyped(na_cast::<O>())),
283 );
284 namespaces.insert(
285 "linefill".to_string(),
286 callable_namespace(linefill::register()),
287 );
288 namespaces.insert("polyline".to_string(), polyline::register());
289 namespaces.insert("table".to_string(), callable_namespace(table::register()));
290 for (name, value) in indicator::register(version) {
291 namespaces.insert(name, value);
292 }
293 for (name, value) in library::register(version) {
294 namespaces.insert(name, value);
295 }
296 namespaces.insert("request".to_string(), request::register());
297 namespaces.insert("strategy".to_string(), strategy::register(version));
298 namespaces.insert("alertcondition".to_string(), alertcondition::register());
299 namespaces.insert("fill".to_string(), fill::register());
300 for (name, value) in globals::register() {
301 namespaces.insert(name, value);
302 }
303
304 namespaces.insert("size".to_string(), constants::size::register());
306 namespaces.insert("shape".to_string(), constants::shape::register());
307 namespaces.insert("location".to_string(), constants::location::register());
308 namespaces.insert("position".to_string(), constants::position::register());
309 namespaces.insert("display".to_string(), constants::display::register());
310 namespaces.insert("format".to_string(), constants::format::register());
311 namespaces.insert("order".to_string(), constants::order::register());
312 namespaces.insert("text".to_string(), constants::text::register());
313 namespaces.insert("xloc".to_string(), constants::xloc::register());
314 namespaces.insert("extend".to_string(), constants::extend::register());
315 namespaces.insert("barmerge".to_string(), constants::barmerge::register());
316 namespaces.insert("yloc".to_string(), constants::yloc::register());
317 namespaces.insert("scale".to_string(), constants::scale::register());
318 namespaces.insert("font".to_string(), constants::font::register());
319 namespaces.insert("splits".to_string(), constants::splits::register());
320 namespaces.insert("adjustment".to_string(), constants::adjustment::register());
321 namespaces.insert(
322 "backadjustment".to_string(),
323 constants::backadjustment::register(),
324 );
325 namespaces.insert(
326 "settlement_as_close".to_string(),
327 constants::settlement_as_close::register(),
328 );
329 namespaces.insert("log".to_string(), log::register());
330 for (name, func) in math::register(version) {
331 namespaces.insert(name, func);
332 }
333 namespaces.insert("matrix".to_string(), matrix::register());
334 for (name, func) in str::register(version) {
335 namespaces.insert(name, func);
336 }
337 let (ta_ns, ta_advance) = ta::register(version);
338 for (name, func) in ta_ns {
339 namespaces.insert(name, func);
340 }
341 advances.push(ta_advance);
342
343 namespaces.insert("na".to_string(), Na::<O>::builtin_value());
345 namespaces.insert("bool".to_string(), Bool::<O>::builtin_value());
346 namespaces.insert("int".to_string(), Int::<O>::builtin_value());
347 namespaces.insert("float".to_string(), Float::<O>::builtin_value());
348 namespaces.insert("nz".to_string(), Nz::<O>::builtin_value());
349 namespaces.insert("fixnan".to_string(), Fixnan::<O>::builtin_value());
350
351 for (name, func) in time::register_time_functions() {
353 namespaces.insert(name, func);
354 }
355 namespaces.insert("dayofweek".to_string(), time::register_dayofweek());
358 namespaces.insert("time_close".to_string(), time::register_time_close());
359 namespaces.insert(
360 "time_tradingday".to_string(),
361 time::register_time_tradingday(),
362 );
363
364 for (name, func) in plot::register_plot_functions() {
366 namespaces.insert(name, func);
367 }
368
369 (namespaces, advances)
370}
371
372pub fn register_per_bar<O: PineOutput>(bar: &Bar) -> Vec<(String, Value<O>)> {
377 vec![
378 ("barstate".to_string(), barstate::register(bar)),
379 ("timenow".to_string(), time::register_timenow()),
380 ]
381}
382
383pub fn per_bar_variables<O: PineOutput>(
393 bar: &Bar,
394 last_bar: Option<&Bar>,
395) -> Vec<(String, Value<O>)> {
396 let series = |id: &str, value: f64| {
397 (
398 id.to_string(),
399 Value::Series(pine_interpreter::Series {
400 id: id.to_string(),
401 current: Box::new(Value::Number(value)),
402 history: None,
403 }),
404 )
405 };
406 let mut vars = vec![
407 series("open", bar.open),
408 series("high", bar.high),
409 series("low", bar.low),
410 series("close", bar.close),
411 series("volume", bar.volume),
412 series("hl2", (bar.high + bar.low) / 2.0),
413 series("hlc3", (bar.high + bar.low + bar.close) / 3.0),
414 series("hlcc4", (bar.high + bar.low + bar.close * 2.0) / 4.0),
415 series("ohlc4", (bar.open + bar.high + bar.low + bar.close) / 4.0),
416 ("bar_index".to_string(), Value::Number(bar.index as f64)),
417 (
418 "last_bar_index".to_string(),
419 last_bar.map_or(Value::Na, |b| Value::Number(b.index as f64)),
420 ),
421 (
422 "last_bar_time".to_string(),
423 last_bar.map_or(Value::Na, |b| Value::Number(b.time as f64)),
424 ),
425 ];
426 vars.extend(register_per_bar(bar));
427 vars
428}
429
430#[cfg(test)]
431mod tests {
432 use super::*;
433 use pine_interpreter::{EvaluatedArg, FunctionCallArgs};
434
435 #[test]
436 fn test_na() {
437 let mut ctx = Interpreter::<DefaultPineOutput>::new();
438
439 let args = vec![EvaluatedArg::Positional(Value::Na)];
441 let result = Na::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
442 assert_eq!(result, Value::Bool(true));
443
444 let args = vec![EvaluatedArg::Positional(Value::Number(42.0))];
446 let result = Na::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
447 assert_eq!(result, Value::Bool(false));
448
449 let args = vec![EvaluatedArg::Positional(Value::String("hello".to_string()))];
451 let result = Na::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
452 assert_eq!(result, Value::Bool(false));
453
454 let args = vec![EvaluatedArg::Positional(Value::Bool(true))];
456 let result = Na::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
457 assert_eq!(result, Value::Bool(false));
458 }
459
460 #[test]
461 fn test_bool() {
462 let mut ctx = Interpreter::<DefaultPineOutput>::new();
463
464 let args = vec![EvaluatedArg::Positional(Value::Number(5.0))];
466 let result = Bool::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
467 assert_eq!(result, Value::Bool(true));
468
469 let args = vec![EvaluatedArg::Positional(Value::Number(0.0))];
470 let result = Bool::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
471 assert_eq!(result, Value::Bool(false));
472
473 let args = vec![EvaluatedArg::Positional(Value::Na)];
475 let result = Bool::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
476 assert_eq!(result, Value::Bool(false));
477 }
478
479 #[test]
480 fn test_int() {
481 let mut ctx = Interpreter::<DefaultPineOutput>::new();
482
483 let args = vec![EvaluatedArg::Positional(Value::Number(5.7))];
485 let result = Int::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
486 assert_eq!(result, Value::Number(5.0));
487
488 let args = vec![EvaluatedArg::Positional(Value::Number(-5.7))];
489 let result = Int::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
490 assert_eq!(result, Value::Number(-5.0));
491
492 let args = vec![EvaluatedArg::Positional(Value::Bool(true))];
494 let result = Int::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
495 assert_eq!(result, Value::Number(1.0));
496
497 let args = vec![EvaluatedArg::Positional(Value::Na)];
499 let result = Int::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
500 assert_eq!(result, Value::Na);
501 }
502
503 #[test]
504 fn test_float() {
505 let mut ctx = Interpreter::<DefaultPineOutput>::new();
506
507 let args = vec![EvaluatedArg::Positional(Value::Number(5.0))];
509 let result = Float::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
510 assert_eq!(result, Value::Number(5.0));
511
512 let args = vec![EvaluatedArg::Positional(Value::Bool(true))];
514 let result = Float::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
515 assert_eq!(result, Value::Number(1.0));
516
517 let args = vec![EvaluatedArg::Positional(Value::Na)];
519 let result = Float::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
520 assert_eq!(result, Value::Na);
521 }
522
523 #[test]
524 fn test_nz() {
525 let mut ctx = Interpreter::<DefaultPineOutput>::new();
526
527 let args = vec![EvaluatedArg::Positional(Value::Na)];
529 let result = Nz::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
530 assert_eq!(result, Value::Number(0.0));
531
532 let args = vec![
534 EvaluatedArg::Positional(Value::Na),
535 EvaluatedArg::Positional(Value::Number(42.0)),
536 ];
537 let result = Nz::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
538 assert_eq!(result, Value::Number(42.0));
539
540 let args = vec![EvaluatedArg::Positional(Value::Number(5.0))];
542 let result = Nz::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
543 assert_eq!(result, Value::Number(5.0));
544 }
545
546 #[test]
547 fn test_fixnan() {
548 let mut ctx = Interpreter::<DefaultPineOutput>::new();
549
550 let args = vec![EvaluatedArg::Positional(Value::Na)];
552 let result = Fixnan::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
553 assert_eq!(result, Value::Number(0.0));
554
555 let args = vec![EvaluatedArg::Positional(Value::Number(5.0))];
557 let result = Fixnan::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
558 assert_eq!(result, Value::Number(5.0));
559
560 let args = vec![EvaluatedArg::Positional(Value::Number(f64::NAN))];
562 let result = Fixnan::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
563 assert_eq!(result, Value::Number(0.0));
564 }
565}