1use pine_builtin_macro::BuiltinFunction;
2use pine_core::{PineVersion, SymInfo, Timeframe};
3use pine_interpreter::{
4 AlertConditionOutput, BoxOutput, FillOutput, GlobalOutput, IndicatorOutput, InputOutput,
5 LabelOutput, LineOutput, LogOutput, PineOutput, PlotOutput, TableOutput,
6};
7use pine_interpreter::{Interpreter, RuntimeError, Value};
8use std::collections::HashMap;
9
10pub use pine_core::Bar;
12pub use pine_interpreter::BuiltinFn;
13pub use pine_interpreter::DefaultPineOutput;
14pub use pine_interpreter::EvaluatedArg;
15pub use pine_interpreter::LogLevel;
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 line;
31mod log;
32mod math;
33mod matrix;
34mod plot;
35mod request;
36mod str;
37mod strategy;
38mod syminfo;
39mod ta;
40mod table;
41mod time;
42mod timeframe;
43
44#[derive(BuiltinFunction)]
48#[builtin(name = "na")]
49struct Na<O: PineOutput> {
50 value: Value<O>,
51}
52
53impl<O: PineOutput> Na<O> {
54 fn execute(&self, _ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
55 Ok(Value::Bool(matches!(self.value, Value::Na)))
56 }
57}
58
59#[derive(BuiltinFunction)]
61#[builtin(name = "bool")]
62struct Bool<O: PineOutput> {
63 x: Value<O>,
64}
65
66impl<O: PineOutput> Bool<O> {
67 fn execute(&self, _ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
68 match &self.x {
69 Value::Bool(b) => Ok(Value::Bool(*b)),
70 Value::Int(n) => Ok(Value::Bool(*n != 0)),
71 Value::Number(n) => Ok(Value::Bool(*n != 0.0)),
72 Value::Na => Ok(Value::Bool(false)),
73 _ => Ok(Value::Bool(true)),
74 }
75 }
76}
77
78#[derive(BuiltinFunction)]
80#[builtin(name = "int")]
81struct Int<O: PineOutput> {
82 x: Value<O>,
83}
84
85impl<O: PineOutput> Int<O> {
86 fn execute(&self, _ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
87 match &self.x {
88 Value::Int(n) => Ok(Value::Int(*n)),
89 Value::Number(n) => Ok(Value::Int(n.trunc() as i64)),
90 Value::Bool(b) => Ok(Value::Int(if *b { 1 } else { 0 })),
91 Value::Na => Ok(Value::Na),
92 _ => Err(RuntimeError::TypeError(format!(
93 "Cannot convert {:?} to int",
94 self.x
95 ))),
96 }
97 }
98}
99
100#[derive(BuiltinFunction)]
102#[builtin(name = "float")]
103struct Float<O: PineOutput> {
104 x: Value<O>,
105}
106
107impl<O: PineOutput> Float<O> {
108 fn execute(&self, _ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
109 match &self.x {
110 Value::Int(n) => Ok(Value::Number(*n as f64)),
111 Value::Number(n) => Ok(Value::Number(*n)),
112 Value::Bool(b) => Ok(Value::Number(if *b { 1.0 } else { 0.0 })),
113 Value::Na => Ok(Value::Na),
114 _ => Err(RuntimeError::TypeError(format!(
115 "Cannot convert {:?} to float",
116 self.x
117 ))),
118 }
119 }
120}
121
122#[derive(BuiltinFunction)]
124#[builtin(name = "nz")]
125struct Nz<O: PineOutput> {
126 source: Value<O>,
127 #[arg(default = Value::Number(0.0))]
128 replacement: Value<O>,
129}
130
131impl<O: PineOutput> Nz<O> {
132 fn execute(&self, _ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
133 match &self.source {
134 Value::Na => {
135 match &self.replacement {
137 Value::Number(_) => Ok(self.replacement.clone()),
138 _ => Ok(Value::Number(0.0)),
139 }
140 }
141 _ => Ok(self.source.clone()),
142 }
143 }
144}
145
146#[derive(BuiltinFunction)]
148#[builtin(name = "fixnan")]
149struct Fixnan<O: PineOutput> {
150 source: Value<O>,
151}
152
153impl<O: PineOutput> Fixnan<O> {
154 fn execute(&self, _ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
155 match &self.source {
158 Value::Na => {
159 Ok(Value::Number(0.0))
162 }
163 Value::Number(n) if n.is_nan() => Ok(Value::Number(0.0)),
164 _ => Ok(self.source.clone()),
165 }
166 }
167}
168
169pub fn register_namespace_objects<
177 O: PineOutput
178 + LogOutput
179 + PlotOutput
180 + LabelOutput
181 + BoxOutput
182 + InputOutput
183 + LineOutput
184 + TableOutput
185 + IndicatorOutput
186 + GlobalOutput
187 + AlertConditionOutput
188 + FillOutput,
189>(
190 version: PineVersion,
191 syminfo: Option<SymInfo>,
192 timeframe: Option<Timeframe>,
193) -> HashMap<String, Value<O>> {
194 let mut namespaces = HashMap::new();
195
196 namespaces.insert(
199 "syminfo".to_string(),
200 syminfo::create_syminfo(syminfo.unwrap_or_default()),
201 );
202 namespaces.insert(
203 "timeframe".to_string(),
204 timeframe::register(timeframe.unwrap_or_default()),
205 );
206
207 namespaces.insert("array".to_string(), array::register());
209 namespaces.insert("box".to_string(), r#box::register());
210 namespaces.insert("color".to_string(), color::register());
211 namespaces.insert("currency".to_string(), currency::register());
212 for (name, value) in input::register(version) {
213 namespaces.insert(name, value);
214 }
215 namespaces.insert("label".to_string(), label::register());
216 for (name, value) in line::register(version) {
217 namespaces.insert(name, value);
218 }
219 namespaces.insert("table".to_string(), table::register());
220 for (name, value) in indicator::register(version) {
221 namespaces.insert(name, value);
222 }
223 namespaces.insert("request".to_string(), request::register());
224 namespaces.insert("strategy".to_string(), strategy::register(version));
225 namespaces.insert("alertcondition".to_string(), alertcondition::register());
226 namespaces.insert("fill".to_string(), fill::register());
227 for (name, value) in globals::register() {
228 namespaces.insert(name, value);
229 }
230
231 namespaces.insert("size".to_string(), constants::size::register());
233 namespaces.insert("shape".to_string(), constants::shape::register());
234 namespaces.insert("location".to_string(), constants::location::register());
235 namespaces.insert("position".to_string(), constants::position::register());
236 namespaces.insert("display".to_string(), constants::display::register());
237 namespaces.insert("format".to_string(), constants::format::register());
238 namespaces.insert("order".to_string(), constants::order::register());
239 namespaces.insert("text".to_string(), constants::text::register());
240 namespaces.insert("xloc".to_string(), constants::xloc::register());
241 namespaces.insert("extend".to_string(), constants::extend::register());
242 namespaces.insert("barmerge".to_string(), constants::barmerge::register());
243 namespaces.insert("log".to_string(), log::register());
244 for (name, func) in math::register(version) {
245 namespaces.insert(name, func);
246 }
247 namespaces.insert("matrix".to_string(), matrix::register());
248 for (name, func) in str::register(version) {
249 namespaces.insert(name, func);
250 }
251 for (name, func) in ta::register(version) {
252 namespaces.insert(name, func);
253 }
254
255 namespaces.insert("na".to_string(), Na::<O>::builtin_value());
257 namespaces.insert("bool".to_string(), Bool::<O>::builtin_value());
258 namespaces.insert("int".to_string(), Int::<O>::builtin_value());
259 namespaces.insert("float".to_string(), Float::<O>::builtin_value());
260 namespaces.insert("nz".to_string(), Nz::<O>::builtin_value());
261 namespaces.insert("fixnan".to_string(), Fixnan::<O>::builtin_value());
262
263 for (name, func) in time::register_time_functions() {
265 namespaces.insert(name, func);
266 }
267
268 for (name, func) in plot::register_plot_functions() {
270 namespaces.insert(name, func);
271 }
272
273 namespaces
274}
275
276pub fn register_per_bar<O: PineOutput>(bar: &Bar) -> Vec<(String, Value<O>)> {
281 vec![
282 ("barstate".to_string(), barstate::register(bar)),
283 ("time".to_string(), time::register_bar_time(bar)),
284 ("timenow".to_string(), time::register_timenow()),
285 ]
286}
287
288#[cfg(test)]
289mod tests {
290 use super::*;
291 use pine_interpreter::{EvaluatedArg, FunctionCallArgs};
292
293 #[test]
294 fn test_na() {
295 let mut ctx = Interpreter::<DefaultPineOutput>::new();
296
297 let args = vec![EvaluatedArg::Positional(Value::Na)];
299 let result = Na::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
300 assert_eq!(result, Value::Bool(true));
301
302 let args = vec![EvaluatedArg::Positional(Value::Number(42.0))];
304 let result = Na::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
305 assert_eq!(result, Value::Bool(false));
306
307 let args = vec![EvaluatedArg::Positional(Value::String("hello".to_string()))];
309 let result = Na::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
310 assert_eq!(result, Value::Bool(false));
311
312 let args = vec![EvaluatedArg::Positional(Value::Bool(true))];
314 let result = Na::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
315 assert_eq!(result, Value::Bool(false));
316 }
317
318 #[test]
319 fn test_bool() {
320 let mut ctx = Interpreter::<DefaultPineOutput>::new();
321
322 let args = vec![EvaluatedArg::Positional(Value::Number(5.0))];
324 let result = Bool::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
325 assert_eq!(result, Value::Bool(true));
326
327 let args = vec![EvaluatedArg::Positional(Value::Number(0.0))];
328 let result = Bool::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
329 assert_eq!(result, Value::Bool(false));
330
331 let args = vec![EvaluatedArg::Positional(Value::Na)];
333 let result = Bool::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
334 assert_eq!(result, Value::Bool(false));
335 }
336
337 #[test]
338 fn test_int() {
339 let mut ctx = Interpreter::<DefaultPineOutput>::new();
340
341 let args = vec![EvaluatedArg::Positional(Value::Number(5.7))];
343 let result = Int::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
344 assert_eq!(result, Value::Number(5.0));
345
346 let args = vec![EvaluatedArg::Positional(Value::Number(-5.7))];
347 let result = Int::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
348 assert_eq!(result, Value::Number(-5.0));
349
350 let args = vec![EvaluatedArg::Positional(Value::Bool(true))];
352 let result = Int::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
353 assert_eq!(result, Value::Number(1.0));
354
355 let args = vec![EvaluatedArg::Positional(Value::Na)];
357 let result = Int::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
358 assert_eq!(result, Value::Na);
359 }
360
361 #[test]
362 fn test_float() {
363 let mut ctx = Interpreter::<DefaultPineOutput>::new();
364
365 let args = vec![EvaluatedArg::Positional(Value::Number(5.0))];
367 let result = Float::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
368 assert_eq!(result, Value::Number(5.0));
369
370 let args = vec![EvaluatedArg::Positional(Value::Bool(true))];
372 let result = Float::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
373 assert_eq!(result, Value::Number(1.0));
374
375 let args = vec![EvaluatedArg::Positional(Value::Na)];
377 let result = Float::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
378 assert_eq!(result, Value::Na);
379 }
380
381 #[test]
382 fn test_nz() {
383 let mut ctx = Interpreter::<DefaultPineOutput>::new();
384
385 let args = vec![EvaluatedArg::Positional(Value::Na)];
387 let result = Nz::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
388 assert_eq!(result, Value::Number(0.0));
389
390 let args = vec![
392 EvaluatedArg::Positional(Value::Na),
393 EvaluatedArg::Positional(Value::Number(42.0)),
394 ];
395 let result = Nz::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
396 assert_eq!(result, Value::Number(42.0));
397
398 let args = vec![EvaluatedArg::Positional(Value::Number(5.0))];
400 let result = Nz::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
401 assert_eq!(result, Value::Number(5.0));
402 }
403
404 #[test]
405 fn test_fixnan() {
406 let mut ctx = Interpreter::<DefaultPineOutput>::new();
407
408 let args = vec![EvaluatedArg::Positional(Value::Na)];
410 let result = Fixnan::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
411 assert_eq!(result, Value::Number(0.0));
412
413 let args = vec![EvaluatedArg::Positional(Value::Number(5.0))];
415 let result = Fixnan::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
416 assert_eq!(result, Value::Number(5.0));
417
418 let args = vec![EvaluatedArg::Positional(Value::Number(f64::NAN))];
420 let result = Fixnan::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
421 assert_eq!(result, Value::Number(0.0));
422 }
423}