1use pine_builtin_macro::BuiltinFunction;
2use pine_core::{
3 AlertConditionOutput, BoxOutput, FillOutput, GlobalOutput, IndicatorOutput, InputOutput,
4 LabelOutput, LineOutput, LogOutput, 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 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 {
136 Value::Na => Ok(self.replacement.clone()),
137 Value::Number(n) if n.is_nan() => Ok(self.replacement.clone()),
138 _ => Ok(self.source.clone()),
139 }
140 }
141}
142
143#[derive(BuiltinFunction)]
145#[builtin(name = "fixnan")]
146struct Fixnan<O: PineOutput> {
147 source: Value<O>,
148}
149
150impl<O: PineOutput> Fixnan<O> {
151 fn execute(&self, _ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
152 match &self.source {
155 Value::Na => {
156 Ok(Value::Number(0.0))
159 }
160 Value::Number(n) if n.is_nan() => Ok(Value::Number(0.0)),
161 _ => Ok(self.source.clone()),
162 }
163 }
164}
165
166pub fn register_namespace_objects<
174 O: PineOutput
175 + LogOutput
176 + PlotOutput
177 + LabelOutput
178 + BoxOutput
179 + InputOutput
180 + LineOutput
181 + TableOutput
182 + IndicatorOutput
183 + GlobalOutput
184 + AlertConditionOutput
185 + FillOutput,
186>(
187 version: PineVersion,
188 syminfo: Option<SymInfo>,
189 timeframe: Option<Timeframe>,
190) -> HashMap<String, Value<O>> {
191 let mut namespaces = HashMap::new();
192
193 namespaces.insert(
196 "syminfo".to_string(),
197 syminfo::create_syminfo(syminfo.unwrap_or_default()),
198 );
199 namespaces.insert(
200 "timeframe".to_string(),
201 timeframe::register(timeframe.unwrap_or_default()),
202 );
203
204 namespaces.insert("array".to_string(), array::register());
206 namespaces.insert("box".to_string(), r#box::register());
207 namespaces.insert("color".to_string(), color::register());
208 namespaces.insert("currency".to_string(), currency::register());
209 for (name, value) in input::register(version) {
210 namespaces.insert(name, value);
211 }
212 namespaces.insert("label".to_string(), label::register());
213 for (name, value) in line::register(version) {
214 namespaces.insert(name, value);
215 }
216 namespaces.insert("table".to_string(), table::register());
217 for (name, value) in indicator::register(version) {
218 namespaces.insert(name, value);
219 }
220 namespaces.insert("request".to_string(), request::register());
221 namespaces.insert("strategy".to_string(), strategy::register(version));
222 namespaces.insert("alertcondition".to_string(), alertcondition::register());
223 namespaces.insert("fill".to_string(), fill::register());
224 for (name, value) in globals::register() {
225 namespaces.insert(name, value);
226 }
227
228 namespaces.insert("size".to_string(), constants::size::register());
230 namespaces.insert("shape".to_string(), constants::shape::register());
231 namespaces.insert("location".to_string(), constants::location::register());
232 namespaces.insert("position".to_string(), constants::position::register());
233 namespaces.insert("display".to_string(), constants::display::register());
234 namespaces.insert("format".to_string(), constants::format::register());
235 namespaces.insert("order".to_string(), constants::order::register());
236 namespaces.insert("text".to_string(), constants::text::register());
237 namespaces.insert("xloc".to_string(), constants::xloc::register());
238 namespaces.insert("extend".to_string(), constants::extend::register());
239 namespaces.insert("barmerge".to_string(), constants::barmerge::register());
240 namespaces.insert("log".to_string(), log::register());
241 for (name, func) in math::register(version) {
242 namespaces.insert(name, func);
243 }
244 namespaces.insert("matrix".to_string(), matrix::register());
245 for (name, func) in str::register(version) {
246 namespaces.insert(name, func);
247 }
248 for (name, func) in ta::register(version) {
249 namespaces.insert(name, func);
250 }
251
252 namespaces.insert("na".to_string(), Na::<O>::builtin_value());
254 namespaces.insert("bool".to_string(), Bool::<O>::builtin_value());
255 namespaces.insert("int".to_string(), Int::<O>::builtin_value());
256 namespaces.insert("float".to_string(), Float::<O>::builtin_value());
257 namespaces.insert("nz".to_string(), Nz::<O>::builtin_value());
258 namespaces.insert("fixnan".to_string(), Fixnan::<O>::builtin_value());
259
260 for (name, func) in time::register_time_functions() {
262 namespaces.insert(name, func);
263 }
264
265 for (name, func) in plot::register_plot_functions() {
267 namespaces.insert(name, func);
268 }
269
270 namespaces
271}
272
273pub fn register_per_bar<O: PineOutput>(bar: &Bar) -> Vec<(String, Value<O>)> {
278 vec![
279 ("barstate".to_string(), barstate::register(bar)),
280 ("time".to_string(), time::register_bar_time(bar)),
281 ("timenow".to_string(), time::register_timenow()),
282 ]
283}
284
285#[cfg(test)]
286mod tests {
287 use super::*;
288 use pine_interpreter::{EvaluatedArg, FunctionCallArgs};
289
290 #[test]
291 fn test_na() {
292 let mut ctx = Interpreter::<DefaultPineOutput>::new();
293
294 let args = vec![EvaluatedArg::Positional(Value::Na)];
296 let result = Na::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
297 assert_eq!(result, Value::Bool(true));
298
299 let args = vec![EvaluatedArg::Positional(Value::Number(42.0))];
301 let result = Na::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
302 assert_eq!(result, Value::Bool(false));
303
304 let args = vec![EvaluatedArg::Positional(Value::String("hello".to_string()))];
306 let result = Na::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
307 assert_eq!(result, Value::Bool(false));
308
309 let args = vec![EvaluatedArg::Positional(Value::Bool(true))];
311 let result = Na::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
312 assert_eq!(result, Value::Bool(false));
313 }
314
315 #[test]
316 fn test_bool() {
317 let mut ctx = Interpreter::<DefaultPineOutput>::new();
318
319 let args = vec![EvaluatedArg::Positional(Value::Number(5.0))];
321 let result = Bool::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
322 assert_eq!(result, Value::Bool(true));
323
324 let args = vec![EvaluatedArg::Positional(Value::Number(0.0))];
325 let result = Bool::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
326 assert_eq!(result, Value::Bool(false));
327
328 let args = vec![EvaluatedArg::Positional(Value::Na)];
330 let result = Bool::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
331 assert_eq!(result, Value::Bool(false));
332 }
333
334 #[test]
335 fn test_int() {
336 let mut ctx = Interpreter::<DefaultPineOutput>::new();
337
338 let args = vec![EvaluatedArg::Positional(Value::Number(5.7))];
340 let result = Int::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
341 assert_eq!(result, Value::Number(5.0));
342
343 let args = vec![EvaluatedArg::Positional(Value::Number(-5.7))];
344 let result = Int::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
345 assert_eq!(result, Value::Number(-5.0));
346
347 let args = vec![EvaluatedArg::Positional(Value::Bool(true))];
349 let result = Int::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
350 assert_eq!(result, Value::Number(1.0));
351
352 let args = vec![EvaluatedArg::Positional(Value::Na)];
354 let result = Int::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
355 assert_eq!(result, Value::Na);
356 }
357
358 #[test]
359 fn test_float() {
360 let mut ctx = Interpreter::<DefaultPineOutput>::new();
361
362 let args = vec![EvaluatedArg::Positional(Value::Number(5.0))];
364 let result = Float::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
365 assert_eq!(result, Value::Number(5.0));
366
367 let args = vec![EvaluatedArg::Positional(Value::Bool(true))];
369 let result = Float::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
370 assert_eq!(result, Value::Number(1.0));
371
372 let args = vec![EvaluatedArg::Positional(Value::Na)];
374 let result = Float::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
375 assert_eq!(result, Value::Na);
376 }
377
378 #[test]
379 fn test_nz() {
380 let mut ctx = Interpreter::<DefaultPineOutput>::new();
381
382 let args = vec![EvaluatedArg::Positional(Value::Na)];
384 let result = Nz::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
385 assert_eq!(result, Value::Number(0.0));
386
387 let args = vec![
389 EvaluatedArg::Positional(Value::Na),
390 EvaluatedArg::Positional(Value::Number(42.0)),
391 ];
392 let result = Nz::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
393 assert_eq!(result, Value::Number(42.0));
394
395 let args = vec![EvaluatedArg::Positional(Value::Number(5.0))];
397 let result = Nz::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
398 assert_eq!(result, Value::Number(5.0));
399 }
400
401 #[test]
402 fn test_fixnan() {
403 let mut ctx = Interpreter::<DefaultPineOutput>::new();
404
405 let args = vec![EvaluatedArg::Positional(Value::Na)];
407 let result = Fixnan::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
408 assert_eq!(result, Value::Number(0.0));
409
410 let args = vec![EvaluatedArg::Positional(Value::Number(5.0))];
412 let result = Fixnan::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
413 assert_eq!(result, Value::Number(5.0));
414
415 let args = vec![EvaluatedArg::Positional(Value::Number(f64::NAN))];
417 let result = Fixnan::builtin_fn(&mut ctx, FunctionCallArgs::without_types(args)).unwrap();
418 assert_eq!(result, Value::Number(0.0));
419 }
420}