diegobeyl/backtesting
2
1/* =====================================================
2 DONCHIAN BACKTESTING - Modern Dark Theme Styles
3 ===================================================== */
4
5:root {
6 /* Color Palette */
7 --bg-primary: #0d1117;
8 --bg-secondary: #161b22;
9 --bg-tertiary: #21262d;
10 --bg-elevated: #30363d;
11
12 --text-primary: #f0f6fc;
13 --text-secondary: #8b949e;
14 --text-muted: #6e7681;
15
16 --accent-primary: #58a6ff;
17 --accent-secondary: #1f6feb;
18 --accent-gradient: linear-gradient(135deg, #58a6ff 0%, #1f6feb 100%);
19
20 --success: #3fb950;
21 --success-bg: rgba(63, 185, 80, 0.15);
22 --danger: #f85149;
23 --danger-bg: rgba(248, 81, 73, 0.15);
24 --warning: #d29922;
25 --warning-bg: rgba(210, 153, 34, 0.15);
26
27 /* Glassmorphism */
28 --glass-bg: rgba(22, 27, 34, 0.8);
29 --glass-border: rgba(240, 246, 252, 0.1);
30
31 /* Shadows */
32 --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
33 --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.4);
34 --shadow-lg: 0 10px 20px rgba(0, 0, 0, 0.5);
35 --shadow-glow: 0 0 20px rgba(88, 166, 255, 0.3);
36
37 /* Spacing */
38 --spacing-xs: 4px;
39 --spacing-sm: 8px;
40 --spacing-md: 16px;
41 --spacing-lg: 24px;
42 --spacing-xl: 32px;
43
44 /* Border Radius */
45 --radius-sm: 6px;
46 --radius-md: 10px;
47 --radius-lg: 16px;
48 --radius-full: 9999px;
49
50 /* Transitions */
51 --transition-fast: 150ms ease;
52 --transition-normal: 250ms ease;
53 --transition-slow: 400ms ease;
54}
55
56/* =====================================================
57 Base Styles
58 ===================================================== */
59
60* {
61 margin: 0;
62 padding: 0;
63 box-sizing: border-box;
64}
65
66html,
67body {
68 height: 100%;
69}
70
71body {
72 font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
73 background: var(--bg-primary);
74 color: var(--text-primary);
75 line-height: 1.6;
76 overflow-x: hidden;
77}
78
79/* =====================================================
80 App Container
81 ===================================================== */
82
83.app-container {
84 display: flex;
85 flex-direction: column;
86 min-height: 100vh;
87}
88
89/* =====================================================
90 Header
91 ===================================================== */
92
93.header {
94 display: flex;
95 justify-content: space-between;
96 align-items: center;
97 padding: var(--spacing-md) var(--spacing-lg);
98 background: var(--bg-secondary);
99 border-bottom: 1px solid var(--glass-border);
100 position: sticky;
101 top: 0;
102 z-index: 100;
103 backdrop-filter: blur(10px);
104}
105
106.header-left {
107 display: flex;
108 align-items: center;
109 gap: var(--spacing-lg);
110}
111
112.logo {
113 display: flex;
114 align-items: center;
115 gap: var(--spacing-sm);
116 font-size: 1.5rem;
117 font-weight: 700;
118 background: var(--accent-gradient);
119 -webkit-background-clip: text;
120 -webkit-text-fill-color: transparent;
121 background-clip: text;
122}
123
124.logo-icon {
125 font-size: 1.8rem;
126 -webkit-text-fill-color: initial;
127}
128
129.connection-status {
130 display: flex;
131 align-items: center;
132 gap: var(--spacing-sm);
133 padding: var(--spacing-xs) var(--spacing-md);
134 background: var(--bg-tertiary);
135 border-radius: var(--radius-full);
136 font-size: 0.875rem;
137}
138
139.status-dot {
140 width: 8px;
141 height: 8px;
142 border-radius: 50%;
143 background: var(--warning);
144 animation: pulse 2s infinite;
145}
146
147.status-dot.connected {
148 background: var(--success);
149 animation: none;
150}
151
152.status-dot.disconnected {
153 background: var(--danger);
154}
155
156@keyframes pulse {
157
158 0%,
159 100% {
160 opacity: 1;
161 }
162
163 50% {
164 opacity: 0.5;
165 }
166}
167
168/* =====================================================
169 Buttons
170 ===================================================== */
171
172.btn {
173 display: inline-flex;
174 align-items: center;
175 justify-content: center;
176 gap: var(--spacing-sm);
177 padding: var(--spacing-sm) var(--spacing-md);
178 border: none;
179 border-radius: var(--radius-md);
180 font-family: inherit;
181 font-size: 0.875rem;
182 font-weight: 500;
183 cursor: pointer;
184 transition: all var(--transition-fast);
185}
186
187.btn-primary {
188 background: var(--accent-gradient);
189 color: white;
190 box-shadow: var(--shadow-md);
191}
192
193.btn-primary:hover {
194 transform: translateY(-2px);
195 box-shadow: var(--shadow-glow);
196}
197
198.btn-primary:active {
199 transform: translateY(0);
200}
201
202.btn-primary:disabled {
203 opacity: 0.6;
204 cursor: not-allowed;
205 transform: none;
206}
207
208.btn-secondary {
209 background: var(--bg-tertiary);
210 color: var(--text-secondary);
211 border: 1px solid var(--glass-border);
212}
213
214.btn-secondary:hover {
215 background: var(--bg-elevated);
216 color: var(--text-primary);
217}
218
219.btn-run {
220 width: 100%;
221 padding: var(--spacing-md);
222 font-size: 1rem;
223 margin-top: var(--spacing-md);
224}
225
226.btn-icon {
227 font-size: 0.75rem;
228}
229
230/* =====================================================
231 Main Content Layout
232 ===================================================== */
233
234.main-content {
235 display: grid;
236 grid-template-columns: 320px 1fr;
237 flex: 1;
238 overflow: hidden;
239}
240
241/* =====================================================
242 Config Panel (Left Sidebar)
243 ===================================================== */
244
245.config-panel {
246 background: var(--bg-secondary);
247 border-right: 1px solid var(--glass-border);
248 overflow-y: auto;
249 padding: var(--spacing-lg);
250}
251
252.panel-header {
253 display: flex;
254 justify-content: space-between;
255 align-items: center;
256 margin-bottom: var(--spacing-lg);
257}
258
259.panel-header h2 {
260 font-size: 1.125rem;
261 font-weight: 600;
262}
263
264.hot-reload-badge {
265 padding: var(--spacing-xs) var(--spacing-sm);
266 background: var(--success-bg);
267 color: var(--success);
268 border-radius: var(--radius-full);
269 font-size: 0.75rem;
270 font-weight: 500;
271}
272
273/* =====================================================
274 Form Styles
275 ===================================================== */
276
277.config-form {
278 display: flex;
279 flex-direction: column;
280 gap: var(--spacing-lg);
281}
282
283.form-section {
284 background: var(--bg-tertiary);
285 border-radius: var(--radius-md);
286 padding: var(--spacing-md);
287}
288
289.form-section h3 {
290 font-size: 0.875rem;
291 font-weight: 600;
292 color: var(--text-secondary);
293 margin-bottom: var(--spacing-md);
294 text-transform: uppercase;
295 letter-spacing: 0.5px;
296}
297
298.form-row {
299 display: grid;
300 grid-template-columns: repeat(auto-fit, minmax(80px, 1fr));
301 gap: var(--spacing-sm);
302}
303
304.form-group {
305 display: flex;
306 flex-direction: column;
307 gap: var(--spacing-xs);
308 margin-bottom: var(--spacing-sm);
309}
310
311.form-group label {
312 font-size: 0.8125rem;
313 color: var(--text-secondary);
314}
315
316.form-group input,
317.form-group select {
318 width: 100%;
319 padding: var(--spacing-sm) var(--spacing-md);
320 background: var(--bg-primary);
321 border: 1px solid var(--glass-border);
322 border-radius: var(--radius-sm);
323 color: var(--text-primary);
324 font-family: inherit;
325 font-size: 0.875rem;
326 transition: border-color var(--transition-fast);
327}
328
329.form-group input:focus,
330.form-group select:focus {
331 outline: none;
332 border-color: var(--accent-primary);
333 box-shadow: 0 0 0 3px rgba(88, 166, 255, 0.1);
334}
335
336.form-group select {
337 cursor: pointer;
338}
339
340.checkbox-group {
341 flex-direction: row;
342 align-items: center;
343}
344
345.checkbox-group input[type="checkbox"] {
346 width: auto;
347 margin-right: var(--spacing-sm);
348 accent-color: var(--accent-primary);
349}
350
351/* =====================================================
352 Results Panel (Right Side)
353 ===================================================== */
354
355.results-panel {
356 padding: var(--spacing-lg);
357 overflow-y: auto;
358 display: flex;
359 flex-direction: column;
360 gap: var(--spacing-lg);
361}
362
363/* Progress Bar */
364.progress-container {
365 background: var(--bg-secondary);
366 border-radius: var(--radius-md);
367 padding: var(--spacing-md);
368}
369
370.progress-bar {
371 height: 8px;
372 background: var(--bg-tertiary);
373 border-radius: var(--radius-full);
374 overflow: hidden;
375 margin-bottom: var(--spacing-sm);
376}
377
378.progress-fill {
379 height: 100%;
380 background: var(--accent-gradient);
381 border-radius: var(--radius-full);
382 transition: width var(--transition-normal);
383 width: 0%;
384}
385
386.progress-text {
387 font-size: 0.875rem;
388 color: var(--text-secondary);
389}
390
391/* =====================================================
392 Metrics Grid
393 ===================================================== */
394
395.metrics-grid {
396 display: grid;
397 grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
398 gap: var(--spacing-md);
399}
400
401.metric-card {
402 background: var(--bg-secondary);
403 border: 1px solid var(--glass-border);
404 border-radius: var(--radius-md);
405 padding: var(--spacing-md);
406 transition: transform var(--transition-fast), box-shadow var(--transition-fast);
407}
408
409.metric-card:hover {
410 transform: translateY(-2px);
411 box-shadow: var(--shadow-md);
412}
413
414.metric-card.primary {
415 background: var(--accent-gradient);
416 border: none;
417}
418
419.metric-card.primary.positive {
420 background: linear-gradient(135deg, #3fb950 0%, #2ea043 100%);
421 border: none;
422}
423
424.metric-card.primary.negative {
425 background: linear-gradient(135deg, #f85149 0%, #da3633 100%);
426 border: none;
427}
428
429.metric-card.primary .metric-label {
430 color: rgba(255, 255, 255, 0.9);
431}
432
433.metric-card.primary .metric-value,
434.metric-card.primary .metric-subvalue {
435 color: white !important;
436}
437
438.metric-label {
439 font-size: 0.75rem;
440 color: var(--text-muted);
441 text-transform: uppercase;
442 letter-spacing: 0.5px;
443 margin-bottom: var(--spacing-xs);
444}
445
446.metric-value {
447 font-size: 1.5rem;
448 font-weight: 700;
449 color: var(--text-primary);
450}
451
452.metric-value.positive {
453 color: var(--success);
454}
455
456.metric-value.negative {
457 color: var(--danger);
458}
459
460.metric-subvalue {
461 font-size: 0.875rem;
462 color: var(--text-secondary);
463 margin-top: var(--spacing-xs);
464}
465
466/* =====================================================
467 Chart Tabs
468 ===================================================== */
469
470.chart-tabs {
471 display: flex;
472 gap: var(--spacing-sm);
473 background: var(--bg-secondary);
474 padding: var(--spacing-xs);
475 border-radius: var(--radius-md);
476}
477
478.tab-btn {
479 flex: 1;
480 padding: var(--spacing-sm) var(--spacing-md);
481 background: transparent;
482 border: none;
483 border-radius: var(--radius-sm);
484 color: var(--text-secondary);
485 font-family: inherit;
486 font-size: 0.875rem;
487 font-weight: 500;
488 cursor: pointer;
489 transition: all var(--transition-fast);
490}
491
492.tab-btn:hover {
493 color: var(--text-primary);
494 background: var(--bg-tertiary);
495}
496
497.tab-btn.active {
498 background: var(--accent-gradient);
499 color: white;
500}
501
502/* =====================================================
503 Charts Container
504 ===================================================== */
505
506.charts-container {
507 flex: 1;
508 min-height: 400px;
509 background: var(--bg-secondary);
510 border-radius: var(--radius-md);
511 overflow: hidden;
512}
513
514.chart-panel {
515 display: none;
516 height: 100%;
517 padding: var(--spacing-md);
518}
519
520.chart-panel.active {
521 display: block;
522}
523
524.chart {
525 width: 100%;
526 height: 100%;
527 min-height: 400px;
528}
529
530/* =====================================================
531 Trades Table
532 ===================================================== */
533
534.trades-table-container {
535 height: 100%;
536 overflow: auto;
537}
538
539.trades-table {
540 width: 100%;
541 border-collapse: collapse;
542 font-size: 0.875rem;
543}
544
545.trades-table th,
546.trades-table td {
547 padding: var(--spacing-sm) var(--spacing-md);
548 text-align: left;
549 border-bottom: 1px solid var(--glass-border);
550}
551
552.trades-table th {
553 background: var(--bg-tertiary);
554 color: var(--text-secondary);
555 font-weight: 600;
556 text-transform: uppercase;
557 font-size: 0.75rem;
558 letter-spacing: 0.5px;
559 position: sticky;
560 top: 0;
561}
562
563.trades-table tr:hover {
564 background: var(--bg-tertiary);
565}
566
567.trades-table .no-data {
568 text-align: center;
569 color: var(--text-muted);
570 padding: var(--spacing-xl);
571}
572
573.trade-type {
574 display: inline-block;
575 padding: 2px 8px;
576 border-radius: var(--radius-full);
577 font-size: 0.75rem;
578 font-weight: 600;
579}
580
581.trade-type.long {
582 background: var(--success-bg);
583 color: var(--success);
584}
585
586.trade-type.short {
587 background: var(--danger-bg);
588 color: var(--danger);
589}
590
591.pnl-positive {
592 color: var(--success);
593}
594
595.pnl-negative {
596 color: var(--danger);
597}
598
599/* =====================================================
600 Scrollbar Styles
601 ===================================================== */
602
603::-webkit-scrollbar {
604 width: 8px;
605 height: 8px;
606}
607
608::-webkit-scrollbar-track {
609 background: var(--bg-primary);
610}
611
612::-webkit-scrollbar-thumb {
613 background: var(--bg-elevated);
614 border-radius: var(--radius-full);
615}
616
617::-webkit-scrollbar-thumb:hover {
618 background: var(--text-muted);
619}
620
621/* =====================================================
622 Responsive Design
623 ===================================================== */
624
625@media (max-width: 1024px) {
626 .main-content {
627 grid-template-columns: 280px 1fr;
628 }
629}
630
631@media (max-width: 768px) {
632 .main-content {
633 grid-template-columns: 1fr;
634 }
635
636 .config-panel {
637 border-right: none;
638 border-bottom: 1px solid var(--glass-border);
639 max-height: 50vh;
640 }
641
642 .metrics-grid {
643 grid-template-columns: repeat(2, 1fr);
644 }
645}
646
647/* =====================================================
648 Animations
649 ===================================================== */
650
651@keyframes fadeIn {
652 from {
653 opacity: 0;
654 transform: translateY(10px);
655 }
656
657 to {
658 opacity: 1;
659 transform: translateY(0);
660 }
661}
662
663.metric-card {
664 animation: fadeIn 0.3s ease forwards;
665}
666
667.metric-card:nth-child(1) {
668 animation-delay: 0.05s;
669}
670
671.metric-card:nth-child(2) {
672 animation-delay: 0.1s;
673}
674
675.metric-card:nth-child(3) {
676 animation-delay: 0.15s;
677}
678
679.metric-card:nth-child(4) {
680 animation-delay: 0.2s;
681}
682
683.metric-card:nth-child(5) {
684 animation-delay: 0.25s;
685}
686
687.metric-card:nth-child(6) {
688 animation-delay: 0.3s;
689}
690
691/* Loading Animation */
692.loading {
693 position: relative;
694 pointer-events: none;
695}
696
697.loading::after {
698 content: '';
699 position: absolute;
700 inset: 0;
701 background: rgba(13, 17, 23, 0.7);
702 display: flex;
703 align-items: center;
704 justify-content: center;
705}
706
707/* =====================================================
708 Plotly Chart Overrides
709 ===================================================== */
710
711.js-plotly-plot .plotly .modebar {
712 background: var(--bg-tertiary) !important;
713 border-radius: var(--radius-sm);
714}
715
716.js-plotly-plot .plotly .modebar-btn path {
717 fill: var(--text-secondary) !important;
718}
719
720.js-plotly-plot .plotly .modebar-btn:hover path {
721 fill: var(--text-primary) !important;
722}