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)]
78pub struct LineObject {
79 pub x1: f64,
80 pub y1: f64,
81 pub x2: f64,
82 pub y2: f64,
83 pub xloc: String,
84 pub extend: String,
85 pub color: Option<Color>,
86 pub style: String,
87 pub width: f64,
88}
89
90#[derive(Clone, Debug, Default)]
92pub struct TableCell {
93 pub text: String,
94 pub text_color: Option<Color>,
95 pub bgcolor: Option<Color>,
96 pub text_size: String,
97 pub text_halign: String,
98 pub text_valign: String,
99}
100
101#[derive(Clone, Debug)]
103pub struct Table {
104 pub position: String,
105 pub columns: usize,
106 pub rows: usize,
107 pub bgcolor: Option<Color>,
108 pub cells: HashMap<(usize, usize), TableCell>,
109}
110
111#[derive(Clone, Debug)]
112pub struct PineBox {
113 pub left: f64,
114 pub top: f64,
115 pub right: f64,
116 pub bottom: f64,
117 pub border_color: Option<Color>,
118 pub border_width: f64,
119 pub border_style: String,
120 pub extend: String,
121 pub xloc: String,
122 pub bgcolor: Option<Color>,
123 pub text: String,
124 pub text_size: f64,
125 pub text_color: Option<Color>,
126 pub text_halign: String,
127 pub text_valign: String,
128 pub text_wrap: String,
129 pub text_font_family: String,
130}
131
132#[derive(Clone, Debug, Default)]
134pub struct Plot {
135 pub series: f64,
136 pub title: String,
137 pub color: Option<Color>,
138 pub linewidth: f64,
139 pub style: String,
140 pub trackprice: bool,
141 pub histbase: f64,
142 pub offset: f64,
143 pub join: bool,
144 pub editable: bool,
145 pub show_last: Option<f64>,
146 pub display: String,
147 pub format: Option<String>,
148 pub precision: Option<f64>,
149 pub force_overlay: bool,
150 pub linestyle: String,
151}
152
153#[derive(Clone, Debug)]
155pub struct Plotarrow {
156 pub series: f64,
157 pub title: String,
158 pub colorup: Option<Color>,
159 pub colordown: Option<Color>,
160 pub offset: f64,
161 pub minheight: f64,
162 pub maxheight: f64,
163 pub editable: bool,
164 pub show_last: Option<f64>,
165 pub display: String,
166 pub format: Option<String>,
167 pub precision: Option<f64>,
168 pub force_overlay: bool,
169}
170
171#[derive(Clone, Debug)]
173pub struct Plotbar {
174 pub open: f64,
175 pub high: f64,
176 pub low: f64,
177 pub close: f64,
178 pub title: String,
179 pub color: Option<Color>,
180 pub editable: bool,
181 pub show_last: Option<f64>,
182 pub display: String,
183 pub format: Option<String>,
184 pub precision: Option<f64>,
185 pub force_overlay: bool,
186}
187
188#[derive(Clone, Debug)]
190pub struct Plotcandle {
191 pub open: f64,
192 pub high: f64,
193 pub low: f64,
194 pub close: f64,
195 pub title: String,
196 pub color: Option<Color>,
197 pub wickcolor: Option<Color>,
198 pub editable: bool,
199 pub show_last: Option<f64>,
200 pub bordercolor: Option<Color>,
201 pub display: String,
202 pub format: Option<String>,
203 pub precision: Option<f64>,
204 pub force_overlay: bool,
205}
206
207#[derive(Clone, Debug)]
209pub struct Plotchar {
210 pub series: f64,
211 pub title: String,
212 pub char: String,
213 pub location: String,
214 pub color: Option<Color>,
215 pub offset: f64,
216 pub text: String,
217 pub textcolor: Option<Color>,
218 pub editable: bool,
219 pub size: String,
220 pub show_last: Option<f64>,
221 pub display: String,
222 pub format: Option<String>,
223 pub precision: Option<f64>,
224 pub force_overlay: bool,
225}
226
227#[derive(Clone, Debug)]
229pub struct Plotshape {
230 pub series: f64,
231 pub title: String,
232 pub style: String,
233 pub location: String,
234 pub color: Option<Color>,
235 pub offset: f64,
236 pub text: String,
237 pub textcolor: Option<Color>,
238 pub editable: bool,
239 pub size: String,
240 pub show_last: Option<f64>,
241 pub display: String,
242 pub format: Option<String>,
243 pub precision: Option<f64>,
244 pub force_overlay: bool,
245}
246
247#[derive(Debug, Clone, Copy, PartialEq, Eq)]
249pub enum LogLevel {
250 Info,
251 Warning,
252 Error,
253}
254
255#[derive(Debug, Clone)]
257pub struct LogEntry {
258 pub level: LogLevel,
259 pub message: String,
260}
261
262#[derive(Debug, Clone, PartialEq)]
265pub enum InputValue {
266 Int(i64),
267 Float(f64),
268 Bool(bool),
269 Str(String),
270 Color(Color),
271}
272
273#[derive(Debug, Clone)]
279pub struct Input {
280 pub kind: String,
283 pub title: String,
285 pub group: String,
287 pub default: InputValue,
289}
290
291pub trait PineOutput: Default + Clone + std::fmt::Debug + 'static {
296 fn clear(&mut self);
298}
299
300pub trait LogOutput: PineOutput {
302 fn add_log(&mut self, level: LogLevel, message: String);
304 fn get_logs(&self) -> &[LogEntry];
306}
307
308#[macro_export]
315macro_rules! impl_output_traits_delegate {
316 ($type:ty, $field:ident) => {
317 impl $crate::LogOutput for $type {
318 fn add_log(&mut self, level: $crate::LogLevel, message: String) {
319 self.$field.add_log(level, message)
320 }
321 fn get_logs(&self) -> &[$crate::LogEntry] {
322 self.$field.get_logs()
323 }
324 }
325
326 impl $crate::PlotOutput for $type {
327 fn add_plot(&mut self, plot: $crate::Plot) {
328 self.$field.add_plot(plot)
329 }
330 fn plots(&self) -> &[$crate::Plot] {
331 self.$field.plots()
332 }
333 fn add_plotarrow(&mut self, arrow: $crate::Plotarrow) {
334 self.$field.add_plotarrow(arrow)
335 }
336 fn plotarrows(&self) -> &[$crate::Plotarrow] {
337 self.$field.plotarrows()
338 }
339 fn add_plotbar(&mut self, bar: $crate::Plotbar) {
340 self.$field.add_plotbar(bar)
341 }
342 fn plotbars(&self) -> &[$crate::Plotbar] {
343 self.$field.plotbars()
344 }
345 fn add_plotcandle(&mut self, candle: $crate::Plotcandle) {
346 self.$field.add_plotcandle(candle)
347 }
348 fn plotcandles(&self) -> &[$crate::Plotcandle] {
349 self.$field.plotcandles()
350 }
351 fn add_plotchar(&mut self, char: $crate::Plotchar) {
352 self.$field.add_plotchar(char)
353 }
354 fn plotchars(&self) -> &[$crate::Plotchar] {
355 self.$field.plotchars()
356 }
357 fn add_plotshape(&mut self, shape: $crate::Plotshape) {
358 self.$field.add_plotshape(shape)
359 }
360 fn plotshapes(&self) -> &[$crate::Plotshape] {
361 self.$field.plotshapes()
362 }
363 }
364
365 impl $crate::LabelOutput for $type {
366 fn add_label(&mut self, label: $crate::Label) -> usize {
367 self.$field.add_label(label)
368 }
369 fn get_label(&self, id: usize) -> Option<&$crate::Label> {
370 self.$field.get_label(id)
371 }
372 fn get_label_mut(&mut self, id: usize) -> Option<&mut $crate::Label> {
373 self.$field.get_label_mut(id)
374 }
375 fn delete_label(&mut self, id: usize) -> bool {
376 self.$field.delete_label(id)
377 }
378 }
379
380 impl $crate::BoxOutput for $type {
381 fn add_box(&mut self, box_obj: $crate::PineBox) -> usize {
382 self.$field.add_box(box_obj)
383 }
384 fn get_box(&self, id: usize) -> Option<&$crate::PineBox> {
385 self.$field.get_box(id)
386 }
387 fn get_box_mut(&mut self, id: usize) -> Option<&mut $crate::PineBox> {
388 self.$field.get_box_mut(id)
389 }
390 fn delete_box(&mut self, id: usize) -> bool {
391 self.$field.delete_box(id)
392 }
393 }
394
395 impl $crate::InputOutput for $type {
396 fn add_input(&mut self, input: $crate::Input) {
397 self.$field.add_input(input)
398 }
399 fn inputs(&self) -> &[$crate::Input] {
400 self.$field.inputs()
401 }
402 }
403
404 impl $crate::IndicatorOutput for $type {
405 fn set_indicator(&mut self, indicator: $crate::Indicator) {
406 self.$field.set_indicator(indicator)
407 }
408 fn indicator(&self) -> Option<&$crate::Indicator> {
409 self.$field.indicator()
410 }
411 }
412
413 impl $crate::AlertConditionOutput for $type {
414 fn add_alertcondition(&mut self, alert: $crate::AlertCondition) {
415 self.$field.add_alertcondition(alert)
416 }
417 fn alertconditions(&self) -> &[$crate::AlertCondition] {
418 self.$field.alertconditions()
419 }
420 }
421
422 impl $crate::FillOutput for $type {
423 fn add_fill(&mut self, fill: $crate::FillObject) {
424 self.$field.add_fill(fill)
425 }
426 fn fills(&self) -> &[$crate::FillObject] {
427 self.$field.fills()
428 }
429 }
430
431 impl $crate::GlobalOutput for $type {
432 fn set_bgcolor(&mut self, color: Option<$crate::Color>) {
433 self.$field.set_bgcolor(color)
434 }
435 fn set_barcolor(&mut self, color: Option<$crate::Color>) {
436 self.$field.set_barcolor(color)
437 }
438 fn global_context(&self) -> &$crate::GlobalContext {
439 self.$field.global_context()
440 }
441 }
442
443 impl $crate::LineOutput for $type {
444 fn add_line(&mut self, line: $crate::LineObject) -> usize {
445 self.$field.add_line(line)
446 }
447 fn get_line(&self, id: usize) -> Option<&$crate::LineObject> {
448 self.$field.get_line(id)
449 }
450 fn get_line_mut(&mut self, id: usize) -> Option<&mut $crate::LineObject> {
451 self.$field.get_line_mut(id)
452 }
453 fn delete_line(&mut self, id: usize) -> bool {
454 self.$field.delete_line(id)
455 }
456 }
457
458 impl $crate::TableOutput for $type {
459 fn add_table(&mut self, table: $crate::Table) -> usize {
460 self.$field.add_table(table)
461 }
462 fn get_table(&self, id: usize) -> Option<&$crate::Table> {
463 self.$field.get_table(id)
464 }
465 fn get_table_mut(&mut self, id: usize) -> Option<&mut $crate::Table> {
466 self.$field.get_table_mut(id)
467 }
468 fn delete_table(&mut self, id: usize) -> bool {
469 self.$field.delete_table(id)
470 }
471 }
472 };
473}
474
475pub trait PlotOutput: PineOutput {
477 fn add_plot(&mut self, plot: Plot);
479 fn plots(&self) -> &[Plot];
481
482 fn add_plotarrow(&mut self, arrow: Plotarrow);
484 fn plotarrows(&self) -> &[Plotarrow];
486
487 fn add_plotbar(&mut self, bar: Plotbar);
489 fn plotbars(&self) -> &[Plotbar];
491
492 fn add_plotcandle(&mut self, candle: Plotcandle);
494 fn plotcandles(&self) -> &[Plotcandle];
496
497 fn add_plotchar(&mut self, char: Plotchar);
499 fn plotchars(&self) -> &[Plotchar];
501
502 fn add_plotshape(&mut self, shape: Plotshape);
504 fn plotshapes(&self) -> &[Plotshape];
506}
507
508pub trait LabelOutput: PineOutput {
510 fn add_label(&mut self, label: Label) -> usize;
512 fn get_label(&self, id: usize) -> Option<&Label>;
514 fn get_label_mut(&mut self, id: usize) -> Option<&mut Label>;
516 fn delete_label(&mut self, id: usize) -> bool;
518}
519
520pub trait BoxOutput: PineOutput {
522 fn add_box(&mut self, box_obj: PineBox) -> usize;
524 fn get_box(&self, id: usize) -> Option<&PineBox>;
526 fn get_box_mut(&mut self, id: usize) -> Option<&mut PineBox>;
528 fn delete_box(&mut self, id: usize) -> bool;
530}
531
532pub trait TableOutput: PineOutput {
534 fn add_table(&mut self, table: Table) -> usize;
536 fn get_table(&self, id: usize) -> Option<&Table>;
538 fn get_table_mut(&mut self, id: usize) -> Option<&mut Table>;
540 fn delete_table(&mut self, id: usize) -> bool;
542}
543
544pub trait LineOutput: PineOutput {
546 fn add_line(&mut self, line: LineObject) -> usize;
548 fn get_line(&self, id: usize) -> Option<&LineObject>;
550 fn get_line_mut(&mut self, id: usize) -> Option<&mut LineObject>;
552 fn delete_line(&mut self, id: usize) -> bool;
554}
555
556pub trait FillOutput: PineOutput {
558 fn add_fill(&mut self, fill: FillObject);
559 fn fills(&self) -> &[FillObject];
560}
561
562pub trait GlobalOutput: PineOutput {
564 fn set_bgcolor(&mut self, color: Option<Color>);
565 fn set_barcolor(&mut self, color: Option<Color>);
566 fn global_context(&self) -> &GlobalContext;
568}
569
570pub trait AlertConditionOutput: PineOutput {
572 fn add_alertcondition(&mut self, alert: AlertCondition);
574 fn alertconditions(&self) -> &[AlertCondition];
576}
577
578pub trait IndicatorOutput: PineOutput {
580 fn set_indicator(&mut self, indicator: Indicator);
582 fn indicator(&self) -> Option<&Indicator>;
584}
585
586pub trait InputOutput: PineOutput {
588 fn add_input(&mut self, input: Input);
590 fn inputs(&self) -> &[Input];
592}
593
594#[derive(Default, Clone, Debug)]
596pub struct DefaultPineOutput {
597 labels: HashMap<usize, Label>,
599 next_label_id: usize,
601 boxes: HashMap<usize, PineBox>,
603 next_box_id: usize,
605 lines: HashMap<usize, LineObject>,
607 next_line_id: usize,
609 tables: HashMap<usize, Table>,
611 next_table_id: usize,
613 plots: Vec<Plot>,
615 plotarrows: Vec<Plotarrow>,
617 plotbars: Vec<Plotbar>,
619 plotcandles: Vec<Plotcandle>,
621 plotchars: Vec<Plotchar>,
623 plotshapes: Vec<Plotshape>,
625 logs: Vec<LogEntry>,
627 inputs: Vec<Input>,
629 indicator: Option<Indicator>,
631 globals: GlobalContext,
633 alertconditions: Vec<AlertCondition>,
635 fills: Vec<FillObject>,
637}
638
639impl PineOutput for DefaultPineOutput {
640 fn clear(&mut self) {
641 self.labels.clear();
642 self.boxes.clear();
643 self.plots.clear();
644 self.plotarrows.clear();
645 self.plotbars.clear();
646 self.plotcandles.clear();
647 self.plotchars.clear();
648 self.plotshapes.clear();
649 self.logs.clear();
650 self.inputs.clear();
651 self.indicator = None;
652 self.globals = GlobalContext::default();
653 self.alertconditions.clear();
654 self.fills.clear();
655 self.lines.clear();
656 self.tables.clear();
657 self.next_label_id = 0;
659 self.next_box_id = 0;
660 self.next_line_id = 0;
661 self.next_table_id = 0;
662 }
663}
664
665impl LogOutput for DefaultPineOutput {
666 fn add_log(&mut self, level: LogLevel, message: String) {
667 self.logs.push(LogEntry { level, message });
668 }
669
670 fn get_logs(&self) -> &[LogEntry] {
671 &self.logs
672 }
673}
674
675impl PlotOutput for DefaultPineOutput {
676 fn add_plot(&mut self, plot: Plot) {
677 self.plots.push(plot);
678 }
679
680 fn plots(&self) -> &[Plot] {
681 &self.plots
682 }
683
684 fn add_plotarrow(&mut self, arrow: Plotarrow) {
685 self.plotarrows.push(arrow);
686 }
687
688 fn plotarrows(&self) -> &[Plotarrow] {
689 &self.plotarrows
690 }
691
692 fn add_plotbar(&mut self, bar: Plotbar) {
693 self.plotbars.push(bar);
694 }
695
696 fn plotbars(&self) -> &[Plotbar] {
697 &self.plotbars
698 }
699
700 fn add_plotcandle(&mut self, candle: Plotcandle) {
701 self.plotcandles.push(candle);
702 }
703
704 fn plotcandles(&self) -> &[Plotcandle] {
705 &self.plotcandles
706 }
707
708 fn add_plotchar(&mut self, char: Plotchar) {
709 self.plotchars.push(char);
710 }
711
712 fn plotchars(&self) -> &[Plotchar] {
713 &self.plotchars
714 }
715
716 fn add_plotshape(&mut self, shape: Plotshape) {
717 self.plotshapes.push(shape);
718 }
719
720 fn plotshapes(&self) -> &[Plotshape] {
721 &self.plotshapes
722 }
723}
724
725impl LabelOutput for DefaultPineOutput {
726 fn add_label(&mut self, label: Label) -> usize {
727 let id = self.next_label_id;
728 self.next_label_id += 1;
729 self.labels.insert(id, label);
730 id
731 }
732
733 fn get_label(&self, id: usize) -> Option<&Label> {
734 self.labels.get(&id)
735 }
736
737 fn get_label_mut(&mut self, id: usize) -> Option<&mut Label> {
738 self.labels.get_mut(&id)
739 }
740
741 fn delete_label(&mut self, id: usize) -> bool {
742 self.labels.remove(&id).is_some()
743 }
744}
745
746impl BoxOutput for DefaultPineOutput {
747 fn add_box(&mut self, box_obj: PineBox) -> usize {
748 let id = self.next_box_id;
749 self.next_box_id += 1;
750 self.boxes.insert(id, box_obj);
751 id
752 }
753
754 fn get_box(&self, id: usize) -> Option<&PineBox> {
755 self.boxes.get(&id)
756 }
757
758 fn get_box_mut(&mut self, id: usize) -> Option<&mut PineBox> {
759 self.boxes.get_mut(&id)
760 }
761
762 fn delete_box(&mut self, id: usize) -> bool {
763 self.boxes.remove(&id).is_some()
764 }
765}
766
767impl LineOutput for DefaultPineOutput {
768 fn add_line(&mut self, line: LineObject) -> usize {
769 let id = self.next_line_id;
770 self.next_line_id += 1;
771 self.lines.insert(id, line);
772 id
773 }
774
775 fn get_line(&self, id: usize) -> Option<&LineObject> {
776 self.lines.get(&id)
777 }
778
779 fn get_line_mut(&mut self, id: usize) -> Option<&mut LineObject> {
780 self.lines.get_mut(&id)
781 }
782
783 fn delete_line(&mut self, id: usize) -> bool {
784 self.lines.remove(&id).is_some()
785 }
786}
787
788impl TableOutput for DefaultPineOutput {
789 fn add_table(&mut self, table: Table) -> usize {
790 let id = self.next_table_id;
791 self.next_table_id += 1;
792 self.tables.insert(id, table);
793 id
794 }
795
796 fn get_table(&self, id: usize) -> Option<&Table> {
797 self.tables.get(&id)
798 }
799
800 fn get_table_mut(&mut self, id: usize) -> Option<&mut Table> {
801 self.tables.get_mut(&id)
802 }
803
804 fn delete_table(&mut self, id: usize) -> bool {
805 self.tables.remove(&id).is_some()
806 }
807}
808
809impl InputOutput for DefaultPineOutput {
810 fn add_input(&mut self, input: Input) {
811 self.inputs.push(input);
812 }
813
814 fn inputs(&self) -> &[Input] {
815 &self.inputs
816 }
817}
818
819impl IndicatorOutput for DefaultPineOutput {
820 fn set_indicator(&mut self, indicator: Indicator) {
821 self.indicator = Some(indicator);
822 }
823
824 fn indicator(&self) -> Option<&Indicator> {
825 self.indicator.as_ref()
826 }
827}
828
829impl AlertConditionOutput for DefaultPineOutput {
830 fn add_alertcondition(&mut self, alert: AlertCondition) {
831 self.alertconditions.push(alert);
832 }
833
834 fn alertconditions(&self) -> &[AlertCondition] {
835 &self.alertconditions
836 }
837}
838
839impl FillOutput for DefaultPineOutput {
840 fn add_fill(&mut self, fill: FillObject) {
841 self.fills.push(fill);
842 }
843
844 fn fills(&self) -> &[FillObject] {
845 &self.fills
846 }
847}
848
849impl GlobalOutput for DefaultPineOutput {
850 fn set_bgcolor(&mut self, color: Option<Color>) {
851 self.globals.bgcolor = color;
852 }
853
854 fn set_barcolor(&mut self, color: Option<Color>) {
855 self.globals.barcolor = color;
856 }
857
858 fn global_context(&self) -> &GlobalContext {
859 &self.globals
860 }
861}