1use std::collections::HashMap;
4
5#[derive(Clone, Debug, PartialEq)]
7pub struct Color {
8 pub r: u8, pub g: u8, pub b: u8, pub t: u8, }
13
14impl Color {
15 pub fn new(r: u8, g: u8, b: u8, t: u8) -> Self {
16 Color { r, g, b, t }
17 }
18}
19
20#[derive(Clone, Debug)]
22pub struct Label {
23 pub x: f64,
24 pub y: f64,
25 pub text: String,
26 pub xloc: String,
27 pub yloc: String,
28 pub color: Option<Color>,
29 pub style: String,
30 pub textcolor: Option<Color>,
31 pub size: String,
32 pub textalign: String,
33 pub tooltip: Option<String>,
34 pub text_font_family: String,
35}
36
37#[derive(Clone, Debug)]
40pub struct FillObject {
41 pub id1: Option<usize>,
43 pub id2: Option<usize>,
45 pub color: Option<Color>,
46 pub title: String,
47}
48
49#[derive(Clone, Debug, Default)]
51pub struct GlobalContext {
52 pub bgcolor: Option<Color>,
54 pub barcolor: Option<Color>,
56}
57
58#[derive(Clone, Debug, Default)]
60pub struct AlertCondition {
61 pub title: String,
62 pub message: String,
63}
64
65#[derive(Clone, Debug, Default)]
67pub struct Indicator {
68 pub title: String,
69 pub shorttitle: String,
70 pub overlay: bool,
71 pub format: String,
72 pub precision: Option<i64>,
73 pub timeframe: String,
74}
75
76#[derive(Clone, Debug, Default)]
78pub struct Library {
79 pub title: String,
80 pub overlay: bool,
81 pub dynamic_requests: Option<bool>,
82}
83
84#[derive(Clone, Debug)]
86pub struct LineObject {
87 pub x1: f64,
88 pub y1: f64,
89 pub x2: f64,
90 pub y2: f64,
91 pub xloc: String,
92 pub extend: String,
93 pub color: Option<Color>,
94 pub style: String,
95 pub width: f64,
96}
97
98#[derive(Clone, Debug, Default)]
100pub struct TableCell {
101 pub text: String,
102 pub text_color: Option<Color>,
103 pub bgcolor: Option<Color>,
104 pub text_size: String,
105 pub text_halign: String,
106 pub text_valign: String,
107}
108
109#[derive(Clone, Debug)]
111pub struct Table {
112 pub position: String,
113 pub columns: usize,
114 pub rows: usize,
115 pub bgcolor: Option<Color>,
116 pub cells: HashMap<(usize, usize), TableCell>,
117}
118
119#[derive(Clone, Debug)]
120pub struct PineBox {
121 pub left: f64,
122 pub top: f64,
123 pub right: f64,
124 pub bottom: f64,
125 pub border_color: Option<Color>,
126 pub border_width: f64,
127 pub border_style: String,
128 pub extend: String,
129 pub xloc: String,
130 pub bgcolor: Option<Color>,
131 pub text: String,
132 pub text_size: f64,
133 pub text_color: Option<Color>,
134 pub text_halign: String,
135 pub text_valign: String,
136 pub text_wrap: String,
137 pub text_font_family: String,
138}
139
140#[derive(Clone, Debug, Default)]
142pub struct Plot {
143 pub series: f64,
144 pub title: String,
145 pub color: Option<Color>,
146 pub linewidth: f64,
147 pub style: String,
148 pub trackprice: bool,
149 pub histbase: f64,
150 pub offset: f64,
151 pub join: bool,
152 pub editable: bool,
153 pub show_last: Option<f64>,
154 pub display: String,
155 pub format: Option<String>,
156 pub precision: Option<f64>,
157 pub force_overlay: bool,
158 pub linestyle: String,
159}
160
161#[derive(Clone, Debug)]
163pub struct Plotarrow {
164 pub series: f64,
165 pub title: String,
166 pub colorup: Option<Color>,
167 pub colordown: Option<Color>,
168 pub offset: f64,
169 pub minheight: f64,
170 pub maxheight: f64,
171 pub editable: bool,
172 pub show_last: Option<f64>,
173 pub display: String,
174 pub format: Option<String>,
175 pub precision: Option<f64>,
176 pub force_overlay: bool,
177}
178
179#[derive(Clone, Debug)]
181pub struct Plotbar {
182 pub open: f64,
183 pub high: f64,
184 pub low: f64,
185 pub close: f64,
186 pub title: String,
187 pub color: Option<Color>,
188 pub editable: bool,
189 pub show_last: Option<f64>,
190 pub display: String,
191 pub format: Option<String>,
192 pub precision: Option<f64>,
193 pub force_overlay: bool,
194}
195
196#[derive(Clone, Debug)]
198pub struct Plotcandle {
199 pub open: f64,
200 pub high: f64,
201 pub low: f64,
202 pub close: f64,
203 pub title: String,
204 pub color: Option<Color>,
205 pub wickcolor: Option<Color>,
206 pub editable: bool,
207 pub show_last: Option<f64>,
208 pub bordercolor: Option<Color>,
209 pub display: String,
210 pub format: Option<String>,
211 pub precision: Option<f64>,
212 pub force_overlay: bool,
213}
214
215#[derive(Clone, Debug)]
217pub struct Plotchar {
218 pub series: f64,
219 pub title: String,
220 pub char: String,
221 pub location: String,
222 pub color: Option<Color>,
223 pub offset: f64,
224 pub text: String,
225 pub textcolor: Option<Color>,
226 pub editable: bool,
227 pub size: String,
228 pub show_last: Option<f64>,
229 pub display: String,
230 pub format: Option<String>,
231 pub precision: Option<f64>,
232 pub force_overlay: bool,
233}
234
235#[derive(Clone, Debug)]
237pub struct Plotshape {
238 pub series: f64,
239 pub title: String,
240 pub style: String,
241 pub location: String,
242 pub color: Option<Color>,
243 pub offset: f64,
244 pub text: String,
245 pub textcolor: Option<Color>,
246 pub editable: bool,
247 pub size: String,
248 pub show_last: Option<f64>,
249 pub display: String,
250 pub format: Option<String>,
251 pub precision: Option<f64>,
252 pub force_overlay: bool,
253}
254
255#[derive(Debug, Clone, Copy, PartialEq, Eq)]
257pub enum LogLevel {
258 Info,
259 Warning,
260 Error,
261}
262
263#[derive(Debug, Clone)]
265pub struct LogEntry {
266 pub level: LogLevel,
267 pub message: String,
268}
269
270#[derive(Debug, Clone, PartialEq)]
273pub enum InputValue {
274 Int(i64),
275 Float(f64),
276 Bool(bool),
277 Str(String),
278 Color(Color),
279}
280
281#[derive(Debug, Clone)]
287pub struct Input {
288 pub kind: String,
291 pub title: String,
293 pub group: String,
295 pub default: InputValue,
297}
298
299pub trait PineOutput: Default + Clone + std::fmt::Debug + 'static {
304 fn clear(&mut self);
306}
307
308pub trait LogOutput: PineOutput {
310 fn add_log(&mut self, level: LogLevel, message: String);
312 fn get_logs(&self) -> &[LogEntry];
314}
315
316#[macro_export]
323macro_rules! impl_output_traits_delegate {
324 ($type:ty, $field:ident) => {
325 impl $crate::LogOutput for $type {
326 fn add_log(&mut self, level: $crate::LogLevel, message: String) {
327 self.$field.add_log(level, message)
328 }
329 fn get_logs(&self) -> &[$crate::LogEntry] {
330 self.$field.get_logs()
331 }
332 }
333
334 impl $crate::PlotOutput for $type {
335 fn add_plot(&mut self, plot: $crate::Plot) {
336 self.$field.add_plot(plot)
337 }
338 fn plots(&self) -> &[$crate::Plot] {
339 self.$field.plots()
340 }
341 fn add_plotarrow(&mut self, arrow: $crate::Plotarrow) {
342 self.$field.add_plotarrow(arrow)
343 }
344 fn plotarrows(&self) -> &[$crate::Plotarrow] {
345 self.$field.plotarrows()
346 }
347 fn add_plotbar(&mut self, bar: $crate::Plotbar) {
348 self.$field.add_plotbar(bar)
349 }
350 fn plotbars(&self) -> &[$crate::Plotbar] {
351 self.$field.plotbars()
352 }
353 fn add_plotcandle(&mut self, candle: $crate::Plotcandle) {
354 self.$field.add_plotcandle(candle)
355 }
356 fn plotcandles(&self) -> &[$crate::Plotcandle] {
357 self.$field.plotcandles()
358 }
359 fn add_plotchar(&mut self, char: $crate::Plotchar) {
360 self.$field.add_plotchar(char)
361 }
362 fn plotchars(&self) -> &[$crate::Plotchar] {
363 self.$field.plotchars()
364 }
365 fn add_plotshape(&mut self, shape: $crate::Plotshape) {
366 self.$field.add_plotshape(shape)
367 }
368 fn plotshapes(&self) -> &[$crate::Plotshape] {
369 self.$field.plotshapes()
370 }
371 }
372
373 impl $crate::LabelOutput for $type {
374 fn add_label(&mut self, label: $crate::Label) -> usize {
375 self.$field.add_label(label)
376 }
377 fn get_label(&self, id: usize) -> Option<&$crate::Label> {
378 self.$field.get_label(id)
379 }
380 fn get_label_mut(&mut self, id: usize) -> Option<&mut $crate::Label> {
381 self.$field.get_label_mut(id)
382 }
383 fn delete_label(&mut self, id: usize) -> bool {
384 self.$field.delete_label(id)
385 }
386 }
387
388 impl $crate::BoxOutput for $type {
389 fn add_box(&mut self, box_obj: $crate::PineBox) -> usize {
390 self.$field.add_box(box_obj)
391 }
392 fn get_box(&self, id: usize) -> Option<&$crate::PineBox> {
393 self.$field.get_box(id)
394 }
395 fn get_box_mut(&mut self, id: usize) -> Option<&mut $crate::PineBox> {
396 self.$field.get_box_mut(id)
397 }
398 fn delete_box(&mut self, id: usize) -> bool {
399 self.$field.delete_box(id)
400 }
401 }
402
403 impl $crate::InputOutput for $type {
404 fn add_input(&mut self, input: $crate::Input) {
405 self.$field.add_input(input)
406 }
407 fn inputs(&self) -> &[$crate::Input] {
408 self.$field.inputs()
409 }
410 }
411
412 impl $crate::MetadataOutput for $type {
413 fn set_indicator(&mut self, indicator: $crate::Indicator) {
414 self.$field.set_indicator(indicator)
415 }
416 fn indicator(&self) -> Option<&$crate::Indicator> {
417 self.$field.indicator()
418 }
419 fn set_library(&mut self, library: $crate::Library) {
420 self.$field.set_library(library)
421 }
422 fn library(&self) -> Option<&$crate::Library> {
423 self.$field.library()
424 }
425 }
426
427 impl $crate::AlertConditionOutput for $type {
428 fn add_alertcondition(&mut self, alert: $crate::AlertCondition) {
429 self.$field.add_alertcondition(alert)
430 }
431 fn alertconditions(&self) -> &[$crate::AlertCondition] {
432 self.$field.alertconditions()
433 }
434 }
435
436 impl $crate::FillOutput for $type {
437 fn add_fill(&mut self, fill: $crate::FillObject) {
438 self.$field.add_fill(fill)
439 }
440 fn fills(&self) -> &[$crate::FillObject] {
441 self.$field.fills()
442 }
443 }
444
445 impl $crate::GlobalOutput for $type {
446 fn set_bgcolor(&mut self, color: Option<$crate::Color>) {
447 self.$field.set_bgcolor(color)
448 }
449 fn set_barcolor(&mut self, color: Option<$crate::Color>) {
450 self.$field.set_barcolor(color)
451 }
452 fn global_context(&self) -> &$crate::GlobalContext {
453 self.$field.global_context()
454 }
455 }
456
457 impl $crate::LineOutput for $type {
458 fn add_line(&mut self, line: $crate::LineObject) -> usize {
459 self.$field.add_line(line)
460 }
461 fn get_line(&self, id: usize) -> Option<&$crate::LineObject> {
462 self.$field.get_line(id)
463 }
464 fn get_line_mut(&mut self, id: usize) -> Option<&mut $crate::LineObject> {
465 self.$field.get_line_mut(id)
466 }
467 fn delete_line(&mut self, id: usize) -> bool {
468 self.$field.delete_line(id)
469 }
470 }
471
472 impl $crate::TableOutput for $type {
473 fn add_table(&mut self, table: $crate::Table) -> usize {
474 self.$field.add_table(table)
475 }
476 fn get_table(&self, id: usize) -> Option<&$crate::Table> {
477 self.$field.get_table(id)
478 }
479 fn get_table_mut(&mut self, id: usize) -> Option<&mut $crate::Table> {
480 self.$field.get_table_mut(id)
481 }
482 fn delete_table(&mut self, id: usize) -> bool {
483 self.$field.delete_table(id)
484 }
485 }
486 };
487}
488
489pub trait PlotOutput: PineOutput {
491 fn add_plot(&mut self, plot: Plot);
493 fn plots(&self) -> &[Plot];
495
496 fn add_plotarrow(&mut self, arrow: Plotarrow);
498 fn plotarrows(&self) -> &[Plotarrow];
500
501 fn add_plotbar(&mut self, bar: Plotbar);
503 fn plotbars(&self) -> &[Plotbar];
505
506 fn add_plotcandle(&mut self, candle: Plotcandle);
508 fn plotcandles(&self) -> &[Plotcandle];
510
511 fn add_plotchar(&mut self, char: Plotchar);
513 fn plotchars(&self) -> &[Plotchar];
515
516 fn add_plotshape(&mut self, shape: Plotshape);
518 fn plotshapes(&self) -> &[Plotshape];
520}
521
522pub trait LabelOutput: PineOutput {
524 fn add_label(&mut self, label: Label) -> usize;
526 fn get_label(&self, id: usize) -> Option<&Label>;
528 fn get_label_mut(&mut self, id: usize) -> Option<&mut Label>;
530 fn delete_label(&mut self, id: usize) -> bool;
532}
533
534pub trait BoxOutput: PineOutput {
536 fn add_box(&mut self, box_obj: PineBox) -> usize;
538 fn get_box(&self, id: usize) -> Option<&PineBox>;
540 fn get_box_mut(&mut self, id: usize) -> Option<&mut PineBox>;
542 fn delete_box(&mut self, id: usize) -> bool;
544}
545
546pub trait TableOutput: PineOutput {
548 fn add_table(&mut self, table: Table) -> usize;
550 fn get_table(&self, id: usize) -> Option<&Table>;
552 fn get_table_mut(&mut self, id: usize) -> Option<&mut Table>;
554 fn delete_table(&mut self, id: usize) -> bool;
556}
557
558pub trait LineOutput: PineOutput {
560 fn add_line(&mut self, line: LineObject) -> usize;
562 fn get_line(&self, id: usize) -> Option<&LineObject>;
564 fn get_line_mut(&mut self, id: usize) -> Option<&mut LineObject>;
566 fn delete_line(&mut self, id: usize) -> bool;
568}
569
570pub trait FillOutput: PineOutput {
572 fn add_fill(&mut self, fill: FillObject);
573 fn fills(&self) -> &[FillObject];
574}
575
576pub trait GlobalOutput: PineOutput {
578 fn set_bgcolor(&mut self, color: Option<Color>);
579 fn set_barcolor(&mut self, color: Option<Color>);
580 fn global_context(&self) -> &GlobalContext;
582}
583
584pub trait AlertConditionOutput: PineOutput {
586 fn add_alertcondition(&mut self, alert: AlertCondition);
588 fn alertconditions(&self) -> &[AlertCondition];
590}
591
592pub trait MetadataOutput: PineOutput {
595 fn set_indicator(&mut self, indicator: Indicator);
597 fn indicator(&self) -> Option<&Indicator>;
599 fn set_library(&mut self, library: Library);
601 fn library(&self) -> Option<&Library>;
603}
604
605pub trait InputOutput: PineOutput {
607 fn add_input(&mut self, input: Input);
609 fn inputs(&self) -> &[Input];
611}
612
613#[derive(Default, Clone, Debug)]
615pub struct DefaultPineOutput {
616 labels: HashMap<usize, Label>,
618 next_label_id: usize,
620 boxes: HashMap<usize, PineBox>,
622 next_box_id: usize,
624 lines: HashMap<usize, LineObject>,
626 next_line_id: usize,
628 tables: HashMap<usize, Table>,
630 next_table_id: usize,
632 plots: Vec<Plot>,
634 plotarrows: Vec<Plotarrow>,
636 plotbars: Vec<Plotbar>,
638 plotcandles: Vec<Plotcandle>,
640 plotchars: Vec<Plotchar>,
642 plotshapes: Vec<Plotshape>,
644 logs: Vec<LogEntry>,
646 inputs: Vec<Input>,
648 indicator: Option<Indicator>,
650 library: Option<Library>,
652 globals: GlobalContext,
654 alertconditions: Vec<AlertCondition>,
656 fills: Vec<FillObject>,
658}
659
660impl PineOutput for DefaultPineOutput {
661 fn clear(&mut self) {
662 self.labels.clear();
663 self.boxes.clear();
664 self.plots.clear();
665 self.plotarrows.clear();
666 self.plotbars.clear();
667 self.plotcandles.clear();
668 self.plotchars.clear();
669 self.plotshapes.clear();
670 self.logs.clear();
671 self.inputs.clear();
672 self.indicator = None;
673 self.globals = GlobalContext::default();
674 self.alertconditions.clear();
675 self.fills.clear();
676 self.lines.clear();
677 self.tables.clear();
678 self.next_label_id = 0;
680 self.next_box_id = 0;
681 self.next_line_id = 0;
682 self.next_table_id = 0;
683 }
684}
685
686impl LogOutput for DefaultPineOutput {
687 fn add_log(&mut self, level: LogLevel, message: String) {
688 self.logs.push(LogEntry { level, message });
689 }
690
691 fn get_logs(&self) -> &[LogEntry] {
692 &self.logs
693 }
694}
695
696impl PlotOutput for DefaultPineOutput {
697 fn add_plot(&mut self, plot: Plot) {
698 self.plots.push(plot);
699 }
700
701 fn plots(&self) -> &[Plot] {
702 &self.plots
703 }
704
705 fn add_plotarrow(&mut self, arrow: Plotarrow) {
706 self.plotarrows.push(arrow);
707 }
708
709 fn plotarrows(&self) -> &[Plotarrow] {
710 &self.plotarrows
711 }
712
713 fn add_plotbar(&mut self, bar: Plotbar) {
714 self.plotbars.push(bar);
715 }
716
717 fn plotbars(&self) -> &[Plotbar] {
718 &self.plotbars
719 }
720
721 fn add_plotcandle(&mut self, candle: Plotcandle) {
722 self.plotcandles.push(candle);
723 }
724
725 fn plotcandles(&self) -> &[Plotcandle] {
726 &self.plotcandles
727 }
728
729 fn add_plotchar(&mut self, char: Plotchar) {
730 self.plotchars.push(char);
731 }
732
733 fn plotchars(&self) -> &[Plotchar] {
734 &self.plotchars
735 }
736
737 fn add_plotshape(&mut self, shape: Plotshape) {
738 self.plotshapes.push(shape);
739 }
740
741 fn plotshapes(&self) -> &[Plotshape] {
742 &self.plotshapes
743 }
744}
745
746impl LabelOutput for DefaultPineOutput {
747 fn add_label(&mut self, label: Label) -> usize {
748 let id = self.next_label_id;
749 self.next_label_id += 1;
750 self.labels.insert(id, label);
751 id
752 }
753
754 fn get_label(&self, id: usize) -> Option<&Label> {
755 self.labels.get(&id)
756 }
757
758 fn get_label_mut(&mut self, id: usize) -> Option<&mut Label> {
759 self.labels.get_mut(&id)
760 }
761
762 fn delete_label(&mut self, id: usize) -> bool {
763 self.labels.remove(&id).is_some()
764 }
765}
766
767impl BoxOutput for DefaultPineOutput {
768 fn add_box(&mut self, box_obj: PineBox) -> usize {
769 let id = self.next_box_id;
770 self.next_box_id += 1;
771 self.boxes.insert(id, box_obj);
772 id
773 }
774
775 fn get_box(&self, id: usize) -> Option<&PineBox> {
776 self.boxes.get(&id)
777 }
778
779 fn get_box_mut(&mut self, id: usize) -> Option<&mut PineBox> {
780 self.boxes.get_mut(&id)
781 }
782
783 fn delete_box(&mut self, id: usize) -> bool {
784 self.boxes.remove(&id).is_some()
785 }
786}
787
788impl LineOutput for DefaultPineOutput {
789 fn add_line(&mut self, line: LineObject) -> usize {
790 let id = self.next_line_id;
791 self.next_line_id += 1;
792 self.lines.insert(id, line);
793 id
794 }
795
796 fn get_line(&self, id: usize) -> Option<&LineObject> {
797 self.lines.get(&id)
798 }
799
800 fn get_line_mut(&mut self, id: usize) -> Option<&mut LineObject> {
801 self.lines.get_mut(&id)
802 }
803
804 fn delete_line(&mut self, id: usize) -> bool {
805 self.lines.remove(&id).is_some()
806 }
807}
808
809impl TableOutput for DefaultPineOutput {
810 fn add_table(&mut self, table: Table) -> usize {
811 let id = self.next_table_id;
812 self.next_table_id += 1;
813 self.tables.insert(id, table);
814 id
815 }
816
817 fn get_table(&self, id: usize) -> Option<&Table> {
818 self.tables.get(&id)
819 }
820
821 fn get_table_mut(&mut self, id: usize) -> Option<&mut Table> {
822 self.tables.get_mut(&id)
823 }
824
825 fn delete_table(&mut self, id: usize) -> bool {
826 self.tables.remove(&id).is_some()
827 }
828}
829
830impl InputOutput for DefaultPineOutput {
831 fn add_input(&mut self, input: Input) {
832 self.inputs.push(input);
833 }
834
835 fn inputs(&self) -> &[Input] {
836 &self.inputs
837 }
838}
839
840impl MetadataOutput for DefaultPineOutput {
841 fn set_indicator(&mut self, indicator: Indicator) {
842 self.indicator = Some(indicator);
843 }
844
845 fn indicator(&self) -> Option<&Indicator> {
846 self.indicator.as_ref()
847 }
848
849 fn set_library(&mut self, library: Library) {
850 self.library = Some(library);
851 }
852
853 fn library(&self) -> Option<&Library> {
854 self.library.as_ref()
855 }
856}
857
858impl AlertConditionOutput for DefaultPineOutput {
859 fn add_alertcondition(&mut self, alert: AlertCondition) {
860 self.alertconditions.push(alert);
861 }
862
863 fn alertconditions(&self) -> &[AlertCondition] {
864 &self.alertconditions
865 }
866}
867
868impl FillOutput for DefaultPineOutput {
869 fn add_fill(&mut self, fill: FillObject) {
870 self.fills.push(fill);
871 }
872
873 fn fills(&self) -> &[FillObject] {
874 &self.fills
875 }
876}
877
878impl GlobalOutput for DefaultPineOutput {
879 fn set_bgcolor(&mut self, color: Option<Color>) {
880 self.globals.bgcolor = color;
881 }
882
883 fn set_barcolor(&mut self, color: Option<Color>) {
884 self.globals.barcolor = color;
885 }
886
887 fn global_context(&self) -> &GlobalContext {
888 &self.globals
889 }
890}