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.to_number()? {
102 Some(n) => Ok(Value::Int(n.trunc() as i64)),
103 None => Ok(Value::Na),
104 }
105 }
106}
107
108#[derive(BuiltinFunction)]
110#[builtin(name = "float")]
111struct Float<O: PineOutput> {
112 x: Value<O>,
113}
114
115impl<O: PineOutput> Float<O> {
116 fn execute(&self, _ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
117 match self.x.to_number()? {
120 Some(n) => Ok(Value::Number(n)),
121 None => Ok(Value::Na),
122 }
123 }
124}
125
126#[derive(BuiltinFunction)]
128#[builtin(name = "nz")]
129struct Nz<O: PineOutput> {
130 source: Value<O>,
131 #[arg(default = Value::Number(0.0))]
132 replacement: Value<O>,
133}
134
135impl<O: PineOutput> Nz<O> {
136 fn execute(&self, _ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
137 match &self.source {
140 Value::Na => Ok(self.replacement.clone()),
141 Value::Number(n) if n.is_nan() => Ok(self.replacement.clone()),
142 _ => Ok(self.source.clone()),
143 }
144 }
145}
146
147#[derive(BuiltinFunction)]
149#[builtin(name = "fixnan")]
150struct Fixnan<O: PineOutput> {
151 source: Value<O>,
152}
153
154impl<O: PineOutput> Fixnan<O> {
155 fn execute(&self, _ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
156 match &self.source {
159 Value::Na => {
160 Ok(Value::Number(0.0))
163 }
164 Value::Number(n) if n.is_nan() => Ok(Value::Number(0.0)),
165 _ => Ok(self.source.clone()),
166 }
167 }
168}
169
170fn na_cast<O: PineOutput>() -> BuiltinFn<O> {
173 Rc::new(|_ctx, call_args| {
174 Ok(match call_args.args.into_iter().next() {
175 Some(EvaluatedArg::Positional(v)) => v,
176 Some(EvaluatedArg::Named { value, .. }) => value,
177 None => Value::Na,
178 })
179 })
180}
181
182fn callable_namespace<O: PineOutput>(namespace: Value<O>) -> Value<O> {
185 match namespace {
186 Value::Object {
187 type_name,
188 fields,
189 value,
190 ..
191 } => Value::Object {
192 type_name,
193 fields,
194 value,
195 call: Some(Builtin::untyped(na_cast::<O>())),
196 },
197 other => other,
198 }
199}
200
201pub fn register_namespace_objects<
209 O: PineOutput
210 + LogOutput
211 + PlotOutput
212 + LabelOutput
213 + BoxOutput
214 + InputOutput
215 + LineOutput
216 + TableOutput
217 + MetadataOutput
218 + GlobalOutput
219 + AlertConditionOutput
220 + FillOutput
221 + DrawingOutput,
222>(
223 version: PineVersion,
224 syminfo: Option<SymInfo>,
225 timeframe: Option<Timeframe>,
226) -> (
227 HashMap<String, Value<O>>,
228 Vec<pine_interpreter::PerBarAdvance<O>>,
229) {
230 let mut namespaces = HashMap::new();
231 let mut advances = Vec::new();
232
233 namespaces.insert(
236 "syminfo".to_string(),
237 syminfo::create_syminfo(syminfo.unwrap_or_default()),
238 );
239 namespaces.insert(
240 "timeframe".to_string(),
241 timeframe::register(timeframe.unwrap_or_default()),
242 );
243
244 namespaces.insert("array".to_string(), array::register());
246 namespaces.insert("box".to_string(), callable_namespace(r#box::register()));
247 namespaces.insert("chart".to_string(), chart::register());
248 namespaces.insert("color".to_string(), callable_namespace(color::register()));
249 namespaces.insert("map".to_string(), map::register());
250 namespaces.insert("session".to_string(), session::register());
251 namespaces.insert("runtime".to_string(), runtime::register());
252 namespaces.insert("alert".to_string(), alertcondition::register_alert());
253 namespaces.insert("ticker".to_string(), ticker::register());
254 namespaces.insert("earnings".to_string(), earnings::register());
255 namespaces.insert("footprint".to_string(), footprint::register_footprint());
256 namespaces.insert("volume_row".to_string(), footprint::register_volume_row());
257 namespaces.insert("dividends".to_string(), dividends::register());
258 namespaces.insert("currency".to_string(), currency::register());
259 for (name, value) in input::register(version) {
260 namespaces.insert(name, value);
261 }
262 namespaces.insert("label".to_string(), callable_namespace(label::register()));
263 for (name, value) in line::register(version) {
264 let value = if name == "line" {
266 callable_namespace(value)
267 } else {
268 value
269 };
270 namespaces.insert(name, value);
271 }
272 namespaces.insert(
273 "string".to_string(),
274 Value::BuiltinFunction(Builtin::untyped(na_cast::<O>())),
275 );
276 namespaces.insert(
277 "linefill".to_string(),
278 callable_namespace(linefill::register()),
279 );
280 namespaces.insert("polyline".to_string(), polyline::register());
281 namespaces.insert("table".to_string(), callable_namespace(table::register()));
282 for (name, value) in indicator::register(version) {
283 namespaces.insert(name, value);
284 }
285 for (name, value) in library::register(version) {
286 namespaces.insert(name, value);
287 }
288 namespaces.insert("request".to_string(), request::register());
289 namespaces.insert("strategy".to_string(), strategy::register(version));
290 namespaces.insert("alertcondition".to_string(), alertcondition::register());
291 namespaces.insert("fill".to_string(), fill::register());
292 for (name, value) in globals::register() {
293 namespaces.insert(name, value);
294 }
295
296 namespaces.insert("size".to_string(), constants::size::register());
298 namespaces.insert("shape".to_string(), constants::shape::register());
299 namespaces.insert("location".to_string(), constants::location::register());
300 namespaces.insert("position".to_string(), constants::position::register());
301 namespaces.insert("display".to_string(), constants::display::register());
302 namespaces.insert("format".to_string(), constants::format::register());
303 namespaces.insert("order".to_string(), constants::order::register());
304 namespaces.insert("text".to_string(), constants::text::register());
305 namespaces.insert("xloc".to_string(), constants::xloc::register());
306 namespaces.insert("extend".to_string(), constants::extend::register());
307 namespaces.insert("barmerge".to_string(), constants::barmerge::register());
308 namespaces.insert("yloc".to_string(), constants::yloc::register());
309 namespaces.insert("scale".to_string(), constants::scale::register());
310 namespaces.insert("font".to_string(), constants::font::register());
311 namespaces.insert("splits".to_string(), constants::splits::register());
312 namespaces.insert("adjustment".to_string(), constants::adjustment::register());
313 namespaces.insert(
314 "backadjustment".to_string(),
315 constants::backadjustment::register(),
316 );
317 namespaces.insert(
318 "settlement_as_close".to_string(),
319 constants::settlement_as_close::register(),
320 );
321 namespaces.insert("log".to_string(), log::register());
322 for (name, func) in math::register(version) {
323 namespaces.insert(name, func);
324 }
325 namespaces.insert("matrix".to_string(), matrix::register());
326 for (name, func) in str::register(version) {
327 namespaces.insert(name, func);
328 }
329 let (ta_ns, ta_advance) = ta::register(version);
330 for (name, func) in ta_ns {
331 namespaces.insert(name, func);
332 }
333 advances.push(ta_advance);
334
335 namespaces.insert("na".to_string(), Na::<O>::builtin_value());
337 namespaces.insert("bool".to_string(), Bool::<O>::builtin_value());
338 namespaces.insert("int".to_string(), Int::<O>::builtin_value());
339 namespaces.insert("float".to_string(), Float::<O>::builtin_value());
340 namespaces.insert("nz".to_string(), Nz::<O>::builtin_value());
341 namespaces.insert("fixnan".to_string(), Fixnan::<O>::builtin_value());
342
343 for (name, func) in time::register_time_functions() {
345 namespaces.insert(name, func);
346 }
347 namespaces.insert("dayofweek".to_string(), time::register_dayofweek());
350 namespaces.insert("time_close".to_string(), time::register_time_close());
351 namespaces.insert(
352 "time_tradingday".to_string(),
353 time::register_time_tradingday(),
354 );
355
356 for (name, func) in plot::register_plot_functions() {
358 namespaces.insert(name, func);
359 }
360
361 (namespaces, advances)
362}
363
364pub fn register_per_bar<O: PineOutput>(bar: &Bar) -> Vec<(String, Value<O>)> {
369 vec![
370 ("barstate".to_string(), barstate::register(bar)),
371 ("timenow".to_string(), time::register_timenow()),
372 ]
373}
374
375pub fn per_bar_variables<O: PineOutput>(
385 bar: &Bar,
386 last_bar: Option<&Bar>,
387) -> Vec<(String, Value<O>)> {
388 let series = |id: &str, value: f64| {
389 (
390 id.to_string(),
391 Value::Series(pine_interpreter::Series {
392 id: id.to_string(),
393 current: Box::new(Value::Number(value)),
394 history: None,
395 }),
396 )
397 };
398 let mut vars = vec![
399 series("open", bar.open),
400 series("high", bar.high),
401 series("low", bar.low),
402 series("close", bar.close),
403 series("volume", bar.volume),
404 series("hl2", (bar.high + bar.low) / 2.0),
405 series("hlc3", (bar.high + bar.low + bar.close) / 3.0),
406 series("hlcc4", (bar.high + bar.low + bar.close * 2.0) / 4.0),
407 series("ohlc4", (bar.open + bar.high + bar.low + bar.close) / 4.0),
408 ("bar_index".to_string(), Value::Number(bar.index as f64)),
409 (
410 "last_bar_index".to_string(),
411 last_bar.map_or(Value::Na, |b| Value::Number(b.index as f64)),
412 ),
413 (
414 "last_bar_time".to_string(),
415 last_bar.map_or(Value::Na, |b| Value::Number(b.time as f64)),
416 ),
417 ];
418 vars.extend(register_per_bar(bar));
419 vars
420}
421
422#[cfg(test)]
423mod tests {
424 use super::*;
425 use pine_interpreter::{EvaluatedArg, FunctionCallArgs};
426
427 #[test]
428 fn test_na() {
429 let mut ctx = Interpreter::<DefaultPineOutput>::new();
430
431 let args = vec![EvaluatedArg::Positional(Value::Na)];
433 let result = Na::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
434 assert_eq!(result, Value::Bool(true));
435
436 let args = vec![EvaluatedArg::Positional(Value::Number(42.0))];
438 let result = Na::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
439 assert_eq!(result, Value::Bool(false));
440
441 let args = vec![EvaluatedArg::Positional(Value::String("hello".to_string()))];
443 let result = Na::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
444 assert_eq!(result, Value::Bool(false));
445
446 let args = vec![EvaluatedArg::Positional(Value::Bool(true))];
448 let result = Na::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
449 assert_eq!(result, Value::Bool(false));
450 }
451
452 #[test]
453 fn test_bool() {
454 let mut ctx = Interpreter::<DefaultPineOutput>::new();
455
456 let args = vec![EvaluatedArg::Positional(Value::Number(5.0))];
458 let result = Bool::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
459 assert_eq!(result, Value::Bool(true));
460
461 let args = vec![EvaluatedArg::Positional(Value::Number(0.0))];
462 let result = Bool::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
463 assert_eq!(result, Value::Bool(false));
464
465 let args = vec![EvaluatedArg::Positional(Value::Na)];
467 let result = Bool::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
468 assert_eq!(result, Value::Bool(false));
469 }
470
471 #[test]
472 fn test_int() {
473 let mut ctx = Interpreter::<DefaultPineOutput>::new();
474
475 let args = vec![EvaluatedArg::Positional(Value::Number(5.7))];
477 let result = Int::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
478 assert_eq!(result, Value::Number(5.0));
479
480 let args = vec![EvaluatedArg::Positional(Value::Number(-5.7))];
481 let result = Int::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
482 assert_eq!(result, Value::Number(-5.0));
483
484 let args = vec![EvaluatedArg::Positional(Value::Bool(true))];
486 let result = Int::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
487 assert_eq!(result, Value::Number(1.0));
488
489 let args = vec![EvaluatedArg::Positional(Value::Na)];
491 let result = Int::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
492 assert_eq!(result, Value::Na);
493 }
494
495 #[test]
496 fn test_float() {
497 let mut ctx = Interpreter::<DefaultPineOutput>::new();
498
499 let args = vec![EvaluatedArg::Positional(Value::Number(5.0))];
501 let result = Float::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
502 assert_eq!(result, Value::Number(5.0));
503
504 let args = vec![EvaluatedArg::Positional(Value::Bool(true))];
506 let result = Float::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
507 assert_eq!(result, Value::Number(1.0));
508
509 let args = vec![EvaluatedArg::Positional(Value::Na)];
511 let result = Float::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
512 assert_eq!(result, Value::Na);
513 }
514
515 #[test]
516 fn test_nz() {
517 let mut ctx = Interpreter::<DefaultPineOutput>::new();
518
519 let args = vec![EvaluatedArg::Positional(Value::Na)];
521 let result = Nz::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
522 assert_eq!(result, Value::Number(0.0));
523
524 let args = vec![
526 EvaluatedArg::Positional(Value::Na),
527 EvaluatedArg::Positional(Value::Number(42.0)),
528 ];
529 let result = Nz::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
530 assert_eq!(result, Value::Number(42.0));
531
532 let args = vec![EvaluatedArg::Positional(Value::Number(5.0))];
534 let result = Nz::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
535 assert_eq!(result, Value::Number(5.0));
536 }
537
538 #[test]
539 fn test_fixnan() {
540 let mut ctx = Interpreter::<DefaultPineOutput>::new();
541
542 let args = vec![EvaluatedArg::Positional(Value::Na)];
544 let result = Fixnan::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
545 assert_eq!(result, Value::Number(0.0));
546
547 let args = vec![EvaluatedArg::Positional(Value::Number(5.0))];
549 let result = Fixnan::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
550 assert_eq!(result, Value::Number(5.0));
551
552 let args = vec![EvaluatedArg::Positional(Value::Number(f64::NAN))];
554 let result = Fixnan::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
555 assert_eq!(result, Value::Number(0.0));
556 }
557}