1use pine_builtin_macro::BuiltinFunction;
2use pine_core::{
3 AlertConditionOutput, BoxOutput, FillOutput, GlobalOutput, InputOutput, LabelOutput,
4 LineOutput, LogOutput, MetadataOutput, PineOutput, PlotOutput, TableOutput,
5};
6use pine_core::{PineVersion, SymInfo, Timeframe};
7use pine_interpreter::{Interpreter, RuntimeError, Value};
8use std::collections::HashMap;
9
10pub use pine_core::Bar;
12pub use pine_core::DefaultPineOutput;
13pub use pine_core::LogLevel;
14pub use pine_interpreter::BuiltinFn;
15pub use pine_interpreter::EvaluatedArg;
16
17mod alertcondition;
19mod array;
20mod barstate;
21mod r#box;
22mod color;
23mod constants;
24mod currency;
25mod fill;
26mod globals;
27mod indicator;
28mod input;
29mod label;
30mod library;
31mod line;
32mod log;
33mod math;
34mod matrix;
35mod plot;
36mod request;
37mod str;
38mod strategy;
39mod syminfo;
40mod ta;
41mod table;
42mod time;
43mod timeframe;
44
45#[derive(BuiltinFunction)]
49#[builtin(name = "na")]
50struct Na<O: PineOutput> {
51 value: Value<O>,
52}
53
54impl<O: PineOutput> Na<O> {
55 fn execute(&self, _ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
56 Ok(Value::Bool(matches!(self.value, Value::Na)))
57 }
58}
59
60#[derive(BuiltinFunction)]
62#[builtin(name = "bool")]
63struct Bool<O: PineOutput> {
64 x: Value<O>,
65}
66
67impl<O: PineOutput> Bool<O> {
68 fn execute(&self, _ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
69 match &self.x {
70 Value::Bool(b) => Ok(Value::Bool(*b)),
71 Value::Int(n) => Ok(Value::Bool(*n != 0)),
72 Value::Number(n) => Ok(Value::Bool(*n != 0.0)),
73 Value::Na => Ok(Value::Bool(false)),
74 _ => Ok(Value::Bool(true)),
75 }
76 }
77}
78
79#[derive(BuiltinFunction)]
81#[builtin(name = "int")]
82struct Int<O: PineOutput> {
83 x: Value<O>,
84}
85
86impl<O: PineOutput> Int<O> {
87 fn execute(&self, _ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
88 match &self.x {
89 Value::Int(n) => Ok(Value::Int(*n)),
90 Value::Number(n) => Ok(Value::Int(n.trunc() as i64)),
91 Value::Bool(b) => Ok(Value::Int(if *b { 1 } else { 0 })),
92 Value::Na => Ok(Value::Na),
93 _ => Err(RuntimeError::TypeError(format!(
94 "Cannot convert {:?} to int",
95 self.x
96 ))),
97 }
98 }
99}
100
101#[derive(BuiltinFunction)]
103#[builtin(name = "float")]
104struct Float<O: PineOutput> {
105 x: Value<O>,
106}
107
108impl<O: PineOutput> Float<O> {
109 fn execute(&self, _ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
110 match &self.x {
111 Value::Int(n) => Ok(Value::Number(*n as f64)),
112 Value::Number(n) => Ok(Value::Number(*n)),
113 Value::Bool(b) => Ok(Value::Number(if *b { 1.0 } else { 0.0 })),
114 Value::Na => Ok(Value::Na),
115 _ => Err(RuntimeError::TypeError(format!(
116 "Cannot convert {:?} to float",
117 self.x
118 ))),
119 }
120 }
121}
122
123#[derive(BuiltinFunction)]
125#[builtin(name = "nz")]
126struct Nz<O: PineOutput> {
127 source: Value<O>,
128 #[arg(default = Value::Number(0.0))]
129 replacement: Value<O>,
130}
131
132impl<O: PineOutput> Nz<O> {
133 fn execute(&self, _ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
134 match &self.source {
137 Value::Na => Ok(self.replacement.clone()),
138 Value::Number(n) if n.is_nan() => Ok(self.replacement.clone()),
139 _ => Ok(self.source.clone()),
140 }
141 }
142}
143
144#[derive(BuiltinFunction)]
146#[builtin(name = "fixnan")]
147struct Fixnan<O: PineOutput> {
148 source: Value<O>,
149}
150
151impl<O: PineOutput> Fixnan<O> {
152 fn execute(&self, _ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
153 match &self.source {
156 Value::Na => {
157 Ok(Value::Number(0.0))
160 }
161 Value::Number(n) if n.is_nan() => Ok(Value::Number(0.0)),
162 _ => Ok(self.source.clone()),
163 }
164 }
165}
166
167pub fn register_namespace_objects<
175 O: PineOutput
176 + LogOutput
177 + PlotOutput
178 + LabelOutput
179 + BoxOutput
180 + InputOutput
181 + LineOutput
182 + TableOutput
183 + MetadataOutput
184 + GlobalOutput
185 + AlertConditionOutput
186 + FillOutput,
187>(
188 version: PineVersion,
189 syminfo: Option<SymInfo>,
190 timeframe: Option<Timeframe>,
191) -> HashMap<String, Value<O>> {
192 let mut namespaces = HashMap::new();
193
194 namespaces.insert(
197 "syminfo".to_string(),
198 syminfo::create_syminfo(syminfo.unwrap_or_default()),
199 );
200 namespaces.insert(
201 "timeframe".to_string(),
202 timeframe::register(timeframe.unwrap_or_default()),
203 );
204
205 namespaces.insert("array".to_string(), array::register());
207 namespaces.insert("box".to_string(), r#box::register());
208 namespaces.insert("color".to_string(), color::register());
209 namespaces.insert("currency".to_string(), currency::register());
210 for (name, value) in input::register(version) {
211 namespaces.insert(name, value);
212 }
213 namespaces.insert("label".to_string(), label::register());
214 for (name, value) in line::register(version) {
215 namespaces.insert(name, value);
216 }
217 namespaces.insert("table".to_string(), table::register());
218 for (name, value) in indicator::register(version) {
219 namespaces.insert(name, value);
220 }
221 for (name, value) in library::register(version) {
222 namespaces.insert(name, value);
223 }
224 namespaces.insert("request".to_string(), request::register());
225 namespaces.insert("strategy".to_string(), strategy::register(version));
226 namespaces.insert("alertcondition".to_string(), alertcondition::register());
227 namespaces.insert("fill".to_string(), fill::register());
228 for (name, value) in globals::register() {
229 namespaces.insert(name, value);
230 }
231
232 namespaces.insert("size".to_string(), constants::size::register());
234 namespaces.insert("shape".to_string(), constants::shape::register());
235 namespaces.insert("location".to_string(), constants::location::register());
236 namespaces.insert("position".to_string(), constants::position::register());
237 namespaces.insert("display".to_string(), constants::display::register());
238 namespaces.insert("format".to_string(), constants::format::register());
239 namespaces.insert("order".to_string(), constants::order::register());
240 namespaces.insert("text".to_string(), constants::text::register());
241 namespaces.insert("xloc".to_string(), constants::xloc::register());
242 namespaces.insert("extend".to_string(), constants::extend::register());
243 namespaces.insert("barmerge".to_string(), constants::barmerge::register());
244 namespaces.insert("log".to_string(), log::register());
245 for (name, func) in math::register(version) {
246 namespaces.insert(name, func);
247 }
248 namespaces.insert("matrix".to_string(), matrix::register());
249 for (name, func) in str::register(version) {
250 namespaces.insert(name, func);
251 }
252 for (name, func) in ta::register(version) {
253 namespaces.insert(name, func);
254 }
255
256 namespaces.insert("na".to_string(), Na::<O>::builtin_value());
258 namespaces.insert("bool".to_string(), Bool::<O>::builtin_value());
259 namespaces.insert("int".to_string(), Int::<O>::builtin_value());
260 namespaces.insert("float".to_string(), Float::<O>::builtin_value());
261 namespaces.insert("nz".to_string(), Nz::<O>::builtin_value());
262 namespaces.insert("fixnan".to_string(), Fixnan::<O>::builtin_value());
263
264 for (name, func) in time::register_time_functions() {
266 namespaces.insert(name, func);
267 }
268
269 for (name, func) in plot::register_plot_functions() {
271 namespaces.insert(name, func);
272 }
273
274 namespaces
275}
276
277pub fn register_per_bar<O: PineOutput>(bar: &Bar) -> Vec<(String, Value<O>)> {
282 vec![
283 ("barstate".to_string(), barstate::register(bar)),
284 ("time".to_string(), time::register_bar_time(bar)),
285 ("timenow".to_string(), time::register_timenow()),
286 ]
287}
288
289pub fn per_bar_variables<O: PineOutput>(bar: &Bar) -> Vec<(String, Value<O>)> {
299 let series = |id: &str, value: f64| {
300 (
301 id.to_string(),
302 Value::Series(pine_interpreter::Series {
303 id: id.to_string(),
304 current: Box::new(Value::Number(value)),
305 }),
306 )
307 };
308 let mut vars = vec![
309 series("open", bar.open),
310 series("high", bar.high),
311 series("low", bar.low),
312 series("close", bar.close),
313 series("volume", bar.volume),
314 series("hl2", (bar.high + bar.low) / 2.0),
315 series("hlc3", (bar.high + bar.low + bar.close) / 3.0),
316 series("hlcc4", (bar.high + bar.low + bar.close * 2.0) / 4.0),
317 series("ohlc4", (bar.open + bar.high + bar.low + bar.close) / 4.0),
318 ("bar_index".to_string(), Value::Number(bar.index as f64)),
319 ];
320 vars.extend(register_per_bar(bar));
321 vars
322}
323
324#[cfg(test)]
325mod tests {
326 use super::*;
327 use pine_interpreter::{EvaluatedArg, FunctionCallArgs};
328
329 #[test]
330 fn test_na() {
331 let mut ctx = Interpreter::<DefaultPineOutput>::new();
332
333 let args = vec![EvaluatedArg::Positional(Value::Na)];
335 let result = Na::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
336 assert_eq!(result, Value::Bool(true));
337
338 let args = vec![EvaluatedArg::Positional(Value::Number(42.0))];
340 let result = Na::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
341 assert_eq!(result, Value::Bool(false));
342
343 let args = vec![EvaluatedArg::Positional(Value::String("hello".to_string()))];
345 let result = Na::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
346 assert_eq!(result, Value::Bool(false));
347
348 let args = vec![EvaluatedArg::Positional(Value::Bool(true))];
350 let result = Na::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
351 assert_eq!(result, Value::Bool(false));
352 }
353
354 #[test]
355 fn test_bool() {
356 let mut ctx = Interpreter::<DefaultPineOutput>::new();
357
358 let args = vec![EvaluatedArg::Positional(Value::Number(5.0))];
360 let result = Bool::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
361 assert_eq!(result, Value::Bool(true));
362
363 let args = vec![EvaluatedArg::Positional(Value::Number(0.0))];
364 let result = Bool::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
365 assert_eq!(result, Value::Bool(false));
366
367 let args = vec![EvaluatedArg::Positional(Value::Na)];
369 let result = Bool::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
370 assert_eq!(result, Value::Bool(false));
371 }
372
373 #[test]
374 fn test_int() {
375 let mut ctx = Interpreter::<DefaultPineOutput>::new();
376
377 let args = vec![EvaluatedArg::Positional(Value::Number(5.7))];
379 let result = Int::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
380 assert_eq!(result, Value::Number(5.0));
381
382 let args = vec![EvaluatedArg::Positional(Value::Number(-5.7))];
383 let result = Int::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
384 assert_eq!(result, Value::Number(-5.0));
385
386 let args = vec![EvaluatedArg::Positional(Value::Bool(true))];
388 let result = Int::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
389 assert_eq!(result, Value::Number(1.0));
390
391 let args = vec![EvaluatedArg::Positional(Value::Na)];
393 let result = Int::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
394 assert_eq!(result, Value::Na);
395 }
396
397 #[test]
398 fn test_float() {
399 let mut ctx = Interpreter::<DefaultPineOutput>::new();
400
401 let args = vec![EvaluatedArg::Positional(Value::Number(5.0))];
403 let result = Float::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
404 assert_eq!(result, Value::Number(5.0));
405
406 let args = vec![EvaluatedArg::Positional(Value::Bool(true))];
408 let result = Float::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
409 assert_eq!(result, Value::Number(1.0));
410
411 let args = vec![EvaluatedArg::Positional(Value::Na)];
413 let result = Float::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
414 assert_eq!(result, Value::Na);
415 }
416
417 #[test]
418 fn test_nz() {
419 let mut ctx = Interpreter::<DefaultPineOutput>::new();
420
421 let args = vec![EvaluatedArg::Positional(Value::Na)];
423 let result = Nz::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
424 assert_eq!(result, Value::Number(0.0));
425
426 let args = vec![
428 EvaluatedArg::Positional(Value::Na),
429 EvaluatedArg::Positional(Value::Number(42.0)),
430 ];
431 let result = Nz::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
432 assert_eq!(result, Value::Number(42.0));
433
434 let args = vec![EvaluatedArg::Positional(Value::Number(5.0))];
436 let result = Nz::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
437 assert_eq!(result, Value::Number(5.0));
438 }
439
440 #[test]
441 fn test_fixnan() {
442 let mut ctx = Interpreter::<DefaultPineOutput>::new();
443
444 let args = vec![EvaluatedArg::Positional(Value::Na)];
446 let result = Fixnan::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
447 assert_eq!(result, Value::Number(0.0));
448
449 let args = vec![EvaluatedArg::Positional(Value::Number(5.0))];
451 let result = Fixnan::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
452 assert_eq!(result, Value::Number(5.0));
453
454 let args = vec![EvaluatedArg::Positional(Value::Number(f64::NAN))];
456 let result = Fixnan::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
457 assert_eq!(result, Value::Number(0.0));
458 }
459}