Mikkka88 commited on
Commit
c54a803
·
verified ·
1 Parent(s): a7cb6e0

ch möchte eine App erstellen die in erster Linie als trading Bot dient. Sie soll Handels Signale die durch pine script Strategien oder Indikatoren auf Tradingview generiert werden, per webhook an meine Exchange wie Bitget, Pionex oder Bybit weiterleiten. Die anbindung zur Exchange läuft über die Exchange Api.

Browse files
Files changed (6) hide show
  1. README.md +8 -5
  2. components/navbar.js +117 -0
  3. components/sidebar.js +180 -0
  4. index.html +154 -19
  5. script.js +228 -0
  6. style.css +204 -18
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Tradeflow Bot
3
- emoji:
4
- colorFrom: red
5
- colorTo: yellow
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
1
  ---
2
+ title: TradeFlow Bot 🚀
3
+ colorFrom: yellow
4
+ colorTo: red
5
+ emoji: 🐳
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite-v3
10
  ---
11
 
12
+ # Welcome to your new DeepSite project!
13
+ This project was created with [DeepSite](https://huggingface.co/deepsite).
components/navbar.js ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // TradeFlow Navbar Component
2
+ class TFNavbar extends HTMLElement {
3
+ constructor() {
4
+ super();
5
+ this.pageTitle = this.getAttribute('page') || 'Dashboard';
6
+ }
7
+
8
+ connectedCallback() {
9
+ this.attachShadow({ mode: 'open' });
10
+ this.render();
11
+ this.setupEventListeners();
12
+ }
13
+
14
+ setupEventListeners() {
15
+ // Mobile menu toggle
16
+ const menuBtn = this.shadowRoot.getElementById('menu-btn');
17
+ const sidebar = document.getElementById('app').querySelector('tf-sidebar');
18
+
19
+ menuBtn?.addEventListener('click', () => {
20
+ const sidebarEl = sidebar.shadowRoot.getElementById('sidebar');
21
+ const overlay = sidebar.shadowRoot.getElementById('overlay');
22
+ sidebarEl.classList.toggle('active');
23
+ overlay.classList.toggle('active');
24
+ });
25
+
26
+ // User menu
27
+ const userBtn = this.shadowRoot.getElementById('user-btn');
28
+ userBtn?.addEventListener('click', () => {
29
+ console.log('User menu clicked');
30
+ });
31
+ }
32
+
33
+ render() {
34
+ this.shadowRoot.innerHTML = `
35
+ <style>
36
+ :host {
37
+ display: block;
38
+ width: 100%;
39
+ }
40
+
41
+ .navbar {
42
+ display: flex;
43
+ align-items: center;
44
+ justify-content: space-between;
45
+ padding: 1rem 1.5rem;
46
+ background: rgba(15, 23, 42, 0.8); /* slate-900 with opacity */
47
+ backdrop-filter: blur(10px);
48
+ border-bottom: 1px solid rgba(148, 163, 184, 0.1);
49
+ }
50
+
51
+ .left-section {
52
+ display: flex;
53
+ align-items: center;
54
+ gap: 1rem;
55
+ }
56
+
57
+ .page-title {
58
+ font-size: 1.5rem;
59
+ font-weight: 700;
60
+ background: linear-gradient(135deg, #f1f5f9, #cbd5e1);
61
+ -webkit-background-clip: text;
62
+ -webkit-text-fill-color: transparent;
63
+ background-clip: text;
64
+ }
65
+
66
+ .menu-btn {
67
+ display: none;
68
+ padding: 0.5rem;
69
+ background: rgba(30, 41, 59, 0.6);
70
+ border: 1px solid rgba(148, 163, 184, 0.2);
71
+ border-radius: 0.5rem;
72
+ color: #94a3b8;
73
+ cursor: pointer;
74
+ transition: all 0.3s ease;
75
+ }
76
+
77
+ .menu-btn:hover {
78
+ background: rgba(30, 41, 59, 0.8);
79
+ color: #f1f5f9;
80
+ }
81
+
82
+ .right-section {
83
+ display: flex;
84
+ align-items: center;
85
+ gap: 1rem;
86
+ }
87
+
88
+ .status-indicator {
89
+ display: flex;
90
+ align-items: center;
91
+ gap: 0.5rem;
92
+ padding: 0.5rem 1rem;
93
+ background: rgba(16, 185, 129, 0.15);
94
+ border: 1px solid rgba(16, 185, 129, 0.3);
95
+ border-radius: 9999px;
96
+ font-size: 0.75rem;
97
+ font-weight: 600;
98
+ color: #10b981;
99
+ }
100
+
101
+ .status-dot {
102
+ width: 6px;
103
+ height: 6px;
104
+ background: #10b981;
105
+ border-radius: 50%;
106
+ animation: pulse 2s infinite;
107
+ }
108
+
109
+ .user-menu {
110
+ display: flex;
111
+ align-items: center;
112
+ gap: 0.75rem;
113
+ padding: 0.5rem 1rem;
114
+ background: rgba(30, 41, 59, 0.6);
115
+ border: 1px solid rgba(148, 163, 184, 0.2);
116
+ border-radius: 0.75rem;
117
+ cursor: pointer
components/sidebar.js ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // TradeFlow Sidebar Component
2
+ class TFSidebar extends HTMLElement {
3
+ constructor() {
4
+ super();
5
+ this.currentPage = this.getCurrentPage();
6
+ }
7
+
8
+ connectedCallback() {
9
+ this.attachShadow({ mode: 'open' });
10
+ this.render();
11
+ }
12
+
13
+ getCurrentPage() {
14
+ const path = window.location.pathname;
15
+ if (path.includes('exchanges')) return 'exchanges';
16
+ if (path.includes('strategies')) return 'strategies';
17
+ if (path.includes('logs')) return 'logs';
18
+ if (path.includes('settings')) return 'settings';
19
+ return 'dashboard';
20
+ }
21
+
22
+ render() {
23
+ const navItems = [
24
+ { id: 'dashboard', label: 'Dashboard', icon: 'layout', href: 'index.html' },
25
+ { id: 'exchanges', label: 'Exchanges', icon: 'server', href: 'exchanges.html' },
26
+ { id: 'strategies', label: 'Strategies', icon: 'code', href: 'strategies.html' },
27
+ { id: 'logs', label: 'Signal Logs', icon: 'activity', href: 'logs.html' },
28
+ { id: 'settings', label: 'Settings', icon: 'settings', href: 'settings.html' }
29
+ ];
30
+
31
+ this.shadowRoot.innerHTML = `
32
+ <style>
33
+ :host {
34
+ display: block;
35
+ height: 100vh;
36
+ position: relative;
37
+ }
38
+
39
+ .sidebar {
40
+ width: 280px;
41
+ height: 100%;
42
+ background: rgba(15, 23, 42, 0.8); /* slate-900 with opacity */
43
+ backdrop-filter: blur(10px);
44
+ border-right: 1px solid rgba(148, 163, 184, 0.1);
45
+ display: flex;
46
+ flex-direction: column;
47
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
48
+ }
49
+
50
+ .logo-section {
51
+ padding: 2rem 1.5rem;
52
+ border-bottom: 1px solid rgba(148, 163, 184, 0.1);
53
+ }
54
+
55
+ .logo {
56
+ display: flex;
57
+ align-items: center;
58
+ gap: 0.75rem;
59
+ font-size: 1.25rem;
60
+ font-weight: 800;
61
+ background: linear-gradient(135deg, #0ea5e9, #8b5cf6);
62
+ -webkit-background-clip: text;
63
+ -webkit-text-fill-color: transparent;
64
+ background-clip: text;
65
+ }
66
+
67
+ .nav-menu {
68
+ flex: 1;
69
+ padding: 1rem 0;
70
+ }
71
+
72
+ .nav-item {
73
+ display: flex;
74
+ align-items: center;
75
+ gap: 0.75rem;
76
+ padding: 0.875rem 1.5rem;
77
+ margin: 0 0.75rem;
78
+ border-radius: 0.75rem;
79
+ text-decoration: none;
80
+ color: #94a3b8; /* slate-400 */
81
+ font-weight: 500;
82
+ transition: all 0.3s ease;
83
+ position: relative;
84
+ }
85
+
86
+ .nav-item:hover {
87
+ background: rgba(30, 41, 59, 0.6);
88
+ color: #f1f5f9; /* slate-100 */
89
+ transform: translateX(4px);
90
+ }
91
+
92
+ .nav-item.active {
93
+ background: linear-gradient(135deg, rgba(14, 165, 233, 0.15), rgba(139, 92, 246, 0.1));
94
+ color: #0ea5e9; /* sky-500 */
95
+ border-left: 4px solid #0ea5e9;
96
+ }
97
+
98
+ .nav-item.active::before {
99
+ content: '';
100
+ position: absolute;
101
+ left: 0;
102
+ top: 0;
103
+ bottom: 0;
104
+ width: 4px;
105
+ background: linear-gradient(to bottom, #0ea5e9, #8b5cf6);
106
+ border-radius: 0 4px 4px 0;
107
+ }
108
+
109
+ .nav-item div {
110
+ display: flex;
111
+ align-items: center;
112
+ gap: 0.75rem;
113
+ }
114
+
115
+ .version {
116
+ margin: 1.5rem;
117
+ padding: 0.75rem;
118
+ background: rgba(30, 41, 59, 0.4);
119
+ border-radius: 0.5rem;
120
+ text-align: center;
121
+ font-size: 0.75rem;
122
+ color: #64748b; /* slate-500 */
123
+ }
124
+
125
+ /* Mobile Overlay */
126
+ .overlay {
127
+ position: fixed;
128
+ inset: 0;
129
+ background: rgba(2, 6, 23, 0.8);
130
+ z-index: 40;
131
+ display: none;
132
+ }
133
+
134
+ .overlay.active {
135
+ display: block;
136
+ }
137
+
138
+ @media (max-width: 768px) {
139
+ .sidebar {
140
+ position: fixed;
141
+ z-index: 50;
142
+ transform: translateX(-100%);
143
+ }
144
+
145
+ .sidebar.active {
146
+ transform: translateX(0);
147
+ }
148
+ }
149
+ </style>
150
+
151
+ <div class="overlay" id="overlay"></div>
152
+ <aside class="sidebar" id="sidebar">
153
+ <div class="logo-section">
154
+ <div class="logo">
155
+ <i data-feather="cpu" width="32" height="32"></i>
156
+ TradeFlow Bot
157
+ </div>
158
+ </div>
159
+
160
+ <nav class="nav-menu">
161
+ ${navItems.map(item => `
162
+ <a href="${item.href}" class="nav-item ${this.currentPage === item.id ? 'active' : ''}" data-page="${item.id}">
163
+ <div>
164
+ <i data-feather="${item.icon}" width="20" height="20"></i>
165
+ ${item.label}
166
+ </div>
167
+ </a>
168
+ `).join('')}
169
+ </nav>
170
+
171
+ <div class="version">
172
+ <i data-feather="git-commit" width="12" height="12"></i>
173
+ v2.1.0-alpha
174
+ </div>
175
+ </aside>
176
+ `;
177
+ }
178
+ }
179
+
180
+ customElements.define('tf-sidebar', TFSidebar);
index.html CHANGED
@@ -1,19 +1,154 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en" class="dark">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>TradeFlow Bot - Dashboard</title>
7
+ <link rel="icon" type="image/x-icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%230ea5e9'%3E%3Cpath d='M3 3h18v18H3V3zm4 4v10h10V7H7z'/%3E%3C/svg%3E">
8
+ <link rel="stylesheet" href="style.css">
9
+ <script src="https://cdn.tailwindcss.com"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
11
+ <script src="https://unpkg.com/feather-icons"></script>
12
+ </head>
13
+ <body class="bg-slate-950 text-slate-100 overflow-hidden">
14
+ <div id="app" class="flex h-screen">
15
+ <!-- Sidebar Component -->
16
+ <tf-sidebar></tf-sidebar>
17
+
18
+ <!-- Main Content -->
19
+ <div class="flex-1 flex flex-col overflow-hidden">
20
+ <!-- Navbar Component -->
21
+ <tf-navbar page="Dashboard"></tf-navbar>
22
+
23
+ <!-- Page Content -->
24
+ <main class="flex-1 overflow-y-auto p-6 space-y-6 gradient-bg">
25
+ <!-- Header Stats -->
26
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
27
+ <tf-stats-card
28
+ title="Active Bots"
29
+ value="12"
30
+ icon="zap"
31
+ color="sky"
32
+ change="+2"
33
+ change-type="positive">
34
+ </tf-stats-card>
35
+ <tf-stats-card
36
+ title="Total PnL"
37
+ value="$2,847.32"
38
+ icon="trending-up"
39
+ color="green"
40
+ change="+12.5%"
41
+ change-type="positive">
42
+ </tf-stats-card>
43
+ <tf-stats-card
44
+ title="Success Rate"
45
+ value="87.3%"
46
+ icon="target"
47
+ color="violet"
48
+ change="+3.2%"
49
+ change-type="positive">
50
+ </tf-stats-card>
51
+ <tf-stats-card
52
+ title="Total Trades"
53
+ value="1,247"
54
+ icon="activity"
55
+ color="orange"
56
+ change="+18"
57
+ change-type="neutral">
58
+ </tf-stats-card>
59
+ </div>
60
+
61
+ <!-- Main Grid -->
62
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
63
+ <!-- Active Signals -->
64
+ <div class="lg:col-span-2 glass-card p-6 rounded-2xl border">
65
+ <div class="flex items-center justify-between mb-6">
66
+ <h2 class="text-xl font-bold flex items-center gap-3">
67
+ <i data-feather="radio" class="text-sky-400"></i>
68
+ Live Signal Feed
69
+ </h2>
70
+ <span class="live-indicator flex items-center gap-2">
71
+ <span class="pulse-dot"></span>
72
+ LIVE
73
+ </span>
74
+ </div>
75
+ <div id="signal-feed" class="space-y-4 max-h-96 overflow-y-auto">
76
+ <!-- Signals populated by JS -->
77
+ </div>
78
+ </div>
79
+
80
+ <!-- Exchange Status -->
81
+ <div class="glass-card p-6 rounded-2xl border">
82
+ <h2 class="text-xl font-bold flex items-center gap-3 mb-6">
83
+ <i data-feather="server" class="text-violet-400"></i>
84
+ Exchange Status
85
+ </h2>
86
+ <div class="space-y-4">
87
+ <tf-exchange-status
88
+ name="Bitget"
89
+ status="connected"
90
+ pairs="BTC/USDT, ETH/USDT">
91
+ </tf-exchange-status>
92
+ <tf-exchange-status
93
+ name="Pionex"
94
+ status="connected"
95
+ pairs="SOL/USDT, AVAX/USDT">
96
+ </tf-exchange-status>
97
+ <tf-exchange-status
98
+ name="Bybit"
99
+ status="disconnected"
100
+ pairs="None">
101
+ </tf-exchange-status>
102
+ </div>
103
+ <button class="w-full mt-6 sky-button px-4 py-3 rounded-lg font-medium flex items-center justify-center gap-2 group">
104
+ <i data-feather="plus" class="w-4 h-4 group-hover:rotate-90 transition-transform"></i>
105
+ Add Exchange
106
+ </button>
107
+ </div>
108
+ </div>
109
+
110
+ <!-- Recent Trades Table -->
111
+ <div class="glass-card p-6 rounded-2xl border">
112
+ <div class="flex items-center justify-between mb-6">
113
+ <h2 class="text-xl font-bold flex items-center gap-3">
114
+ <i data-feather="list" class="text-emerald-400"></i>
115
+ Recent Executions
116
+ </h2>
117
+ <button class="text-slate-400 hover:text-slate-100 transition-colors flex items-center gap-1">
118
+ View All
119
+ <i data-feather="arrow-right" class="w-4 h-4"></i>
120
+ </button>
121
+ </div>
122
+ <div class="overflow-x-auto">
123
+ <table class="w-full text-left">
124
+ <thead>
125
+ <tr class="text-slate-400 border-b border-slate-700">
126
+ <th class="pb-3 font-medium">Time</th>
127
+ <th class="pb-3 font-medium">Pair</th>
128
+ <th class="pb-3 font-medium">Action</th>
129
+ <th class="pb-3 font-medium">Exchange</th>
130
+ <th class="pb-3 font-medium">Status</th>
131
+ <th class="pb-3 font-medium">PnL</th>
132
+ </tr>
133
+ </thead>
134
+ <tbody id="trades-table" class="divide-y divide-slate-800">
135
+ <!-- Populated by JS -->
136
+ </tbody>
137
+ </table>
138
+ </div>
139
+ </div>
140
+ </main>
141
+ </div>
142
+ </div>
143
+
144
+ <!-- Component Scripts -->
145
+ <script src="components/sidebar.js"></script>
146
+ <script src="components/navbar.js"></script>
147
+ <script src="components/stats-card.js"></script>
148
+ <script src="components/status-badge.js"></script>
149
+ <script src="components/exchange-status.js"></script>
150
+ <script src="script.js"></script>
151
+ <script>feather.replace();</script>
152
+ <script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
153
+ </body>
154
+ </html>
script.js ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // TradeFlow Bot - Main JavaScript
2
+
3
+ // Mock Data Generators
4
+ const generateMockSignal = (index = 0) => {
5
+ const actions = ['BUY', 'SELL'];
6
+ const pairs = ['BTC/USDT', 'ETH/USDT', 'SOL/USDT', 'AVAX/USDT', 'MATIC/USDT'];
7
+ const strategies = ['TrendMaster v2.1', 'ScalpPro 3.0', 'MoonSignal Alpha', 'GridFlow Pro'];
8
+ const statuses = ['executed', 'pending', 'failed'];
9
+
10
+ return {
11
+ id: `sig_${Date.now()}_${index}`,
12
+ timestamp: new Date(Date.now() - Math.random() * 3600000),
13
+ pair: pairs[Math.floor(Math.random() * pairs.length)],
14
+ action: actions[Math.floor(Math.random() * actions.length)],
15
+ price: (Math.random() * 50000 + 1000).toFixed(2),
16
+ strategy: strategies[Math.floor(Math.random() * strategies.length)],
17
+ exchange: ['Bitget', 'Pionex', 'Bybit'][Math.floor(Math.random() * 3)],
18
+ status: statuses[Math.floor(Math.random() * statuses.length)],
19
+ pnl: (Math.random() * 200 - 50).toFixed(2)
20
+ };
21
+ };
22
+
23
+ const generateMockTrade = (index = 0) => {
24
+ const signal = generateMockSignal(index);
25
+ return {
26
+ ...signal,
27
+ executionTime: new Date(Date.now() - Math.random() * 86400000),
28
+ filledPrice: (parseFloat(signal.price) * (1 + (Math.random() - 0.5) * 0.001)).toFixed(2),
29
+ filledAmount: (Math.random() * 2 + 0.1).toFixed(4)
30
+ };
31
+ };
32
+
33
+ // DOM Manipulation Helpers
34
+ const formatTime = (date) => {
35
+ return new Intl.DateTimeFormat('en-US', {
36
+ hour: '2-digit',
37
+ minute: '2-digit',
38
+ second: '2-digit',
39
+ hour12: false
40
+ }).format(date);
41
+ };
42
+
43
+ const formatDate = (date) => {
44
+ return new Intl.DateTimeFormat('en-US', {
45
+ month: 'short',
46
+ day: 'numeric',
47
+ hour: '2-digit',
48
+ minute: '2-digit'
49
+ }).format(date);
50
+ };
51
+
52
+ const getStatusBadge = (status) => {
53
+ const classes = {
54
+ 'executed': 'status-connected',
55
+ 'pending': 'status-pending',
56
+ 'failed': 'status-disconnected'
57
+ };
58
+ const icons = {
59
+ 'executed': 'check-circle',
60
+ 'pending': 'clock',
61
+ 'failed': 'x-circle'
62
+ };
63
+ return `
64
+ <span class="status-badge ${classes[status]}">
65
+ <i data-feather="${icons[status]}" class="w-3 h-3"></i>
66
+ ${status}
67
+ </span>
68
+ `;
69
+ };
70
+
71
+ // Signal Feed Manager
72
+ class SignalFeedManager {
73
+ constructor(containerId) {
74
+ this.container = document.getElementById(containerId);
75
+ this.signals = [];
76
+ this.maxSignals = 10;
77
+ }
78
+
79
+ addSignal(signal) {
80
+ this.signals.unshift(signal);
81
+ if (this.signals.length > this.maxSignals) {
82
+ this.signals.pop();
83
+ }
84
+ this.render();
85
+ }
86
+
87
+ render() {
88
+ if (!this.container) return;
89
+
90
+ const signalsHTML = this.signals.map(signal => `
91
+ <div class="signal-item ${signal.action.toLowerCase()} glass-card p-4 rounded-lg border">
92
+ <div class="flex items-center justify-between">
93
+ <div class="flex items-center gap-4">
94
+ <div class="flex flex-col">
95
+ <span class="text-2xl font-bold ${signal.action === 'BUY' ? 'text-emerald-400' : 'text-red-400'}">
96
+ ${signal.action}
97
+ </span>
98
+ <span class="text-xs text-slate-400">${signal.pair}</span>
99
+ </div>
100
+ <div class="flex flex-col">
101
+ <span class="text-lg font-semibold">$${signal.price}</span>
102
+ <span class="text-xs text-slate-400">Price</span>
103
+ </div>
104
+ </div>
105
+ <div class="flex flex-col items-end gap-2">
106
+ <span class="text-sm font-medium">${signal.strategy}</span>
107
+ <span class="text-xs text-slate-400">${signal.exchange}</span>
108
+ <span class="text-xs text-slate-500">${formatTime(signal.timestamp)}</span>
109
+ </div>
110
+ </div>
111
+ <div class="mt-3 flex items-center justify-between">
112
+ ${getStatusBadge(signal.status)}
113
+ <span class="text-xs text-slate-500">${signal.pnl ? `Est. PnL: $${signal.pnl}` : ''}</span>
114
+ </div>
115
+ </div>
116
+ `).join('');
117
+
118
+ this.container.innerHTML = signalsHTML;
119
+ feather.replace();
120
+ }
121
+
122
+ startLiveFeed() {
123
+ // Initial load
124
+ for (let i = 0; i < 5; i++) {
125
+ setTimeout(() => {
126
+ this.addSignal(generateMockSignal(i));
127
+ }, i * 200);
128
+ }
129
+
130
+ // Live updates every 3-7 seconds
131
+ const scheduleNext = () => {
132
+ const delay = Math.random() * 4000 + 3000;
133
+ setTimeout(() => {
134
+ this.addSignal(generateMockSignal());
135
+ scheduleNext();
136
+ }, delay);
137
+ };
138
+ scheduleNext();
139
+ }
140
+ }
141
+
142
+ // Trades Table Manager
143
+ class TradesTableManager {
144
+ constructor(containerId) {
145
+ this.container = document.getElementById(containerId);
146
+ this.trades = [];
147
+ this.maxTrades = 8;
148
+ }
149
+
150
+ addTrade(trade) {
151
+ this.trades.unshift(trade);
152
+ if (this.trades.length > this.maxTrades) {
153
+ this.trades.pop();
154
+ }
155
+ this.render();
156
+ }
157
+
158
+ render() {
159
+ if (!this.container) return;
160
+
161
+ const tradesHTML = this.trades.map(trade => `
162
+ <tr class="hover:bg-slate-800/50 transition-colors">
163
+ <td class="py-4">${formatDate(trade.executionTime)}</td>
164
+ <td class="py-4 font-mono font-semibold">${trade.pair}</td>
165
+ <td class="py-4">
166
+ <span class="font-bold ${trade.action === 'BUY' ? 'text-emerald-400' : 'text-red-400'}">
167
+ ${trade.action}
168
+ </span>
169
+ </td>
170
+ <td class="py-4">${trade.exchange}</td>
171
+ <td class="py-4">${getStatusBadge(trade.status)}</td>
172
+ <td class="py-4 font-semibold ${parseFloat(trade.pnl) > 0 ? 'text-emerald-400' : 'text-red-400'}">
173
+ ${parseFloat(trade.pnl) > 0 ? '+' : ''}$${trade.pnl}
174
+ </td>
175
+ </tr>
176
+ `).join('');
177
+
178
+ this.container.innerHTML = tradesHTML;
179
+ feather.replace();
180
+ }
181
+
182
+ loadInitial() {
183
+ for (let i = 0; i < this.maxTrades; i++) {
184
+ this.trades.push(generateMockTrade(i));
185
+ }
186
+ this.render();
187
+ }
188
+ }
189
+
190
+ // Initialize App
191
+ document.addEventListener('DOMContentLoaded', () => {
192
+ // Initialize signal feed
193
+ const signalManager = new SignalFeedManager('signal-feed');
194
+ signalManager.startLiveFeed();
195
+
196
+ // Initialize trades table
197
+ const tradesManager = new TradesTableManager('trades-table');
198
+ tradesManager.loadInitial();
199
+
200
+ // Auto-update stats
201
+ const updateStats = () => {
202
+ const statsCards = document.querySelectorAll('tf-stats-card');
203
+ statsCards.forEach(card => {
204
+ if (card.getAttribute('title') === 'Total PnL') {
205
+ const currentValue = parseFloat(card.getAttribute('value').replace(/[$,]/g, ''));
206
+ const change = (Math.random() - 0.5) * 100;
207
+ const newValue = (currentValue + change).toFixed(2);
208
+ card.setAttribute('value', `$${newValue.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}`);
209
+ }
210
+ if (card.getAttribute('title') === 'Total Trades') {
211
+ const currentValue = parseInt(card.getAttribute('value'));
212
+ if (Math.random() > 0.8) {
213
+ card.setAttribute('value', (currentValue + 1).toString());
214
+ }
215
+ }
216
+ });
217
+ };
218
+
219
+ // Update stats every 10 seconds
220
+ setInterval(updateStats, 10000);
221
+
222
+ // Page navigation
223
+ window.navigateTo = (page) => {
224
+ window.location.href = page;
225
+ };
226
+
227
+ console.log('🚀 TradeFlow Bot initialized successfully');
228
+ });
style.css CHANGED
@@ -1,28 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  body {
2
- padding: 2rem;
3
- font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  }
5
 
6
- h1 {
7
- font-size: 16px;
8
- margin-top: 0;
 
9
  }
10
 
11
- p {
12
- color: rgb(107, 114, 128);
13
- font-size: 15px;
14
- margin-bottom: 10px;
15
- margin-top: 5px;
16
  }
17
 
18
- .card {
19
- max-width: 620px;
20
- margin: 0 auto;
21
- padding: 16px;
22
- border: 1px solid lightgray;
23
- border-radius: 16px;
24
  }
25
 
26
- .card p:last-child {
27
- margin-bottom: 0;
28
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Custom CSS for TradeFlow Bot - Glassmorphism & Animations */
2
+
3
+ /* Custom Font Import */
4
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap');
5
+
6
+ /* Root Variables */
7
+ :root {
8
+ --primary: #0ea5e9; /* sky-500 */
9
+ --primary-dark: #0284c7; /* sky-600 */
10
+ --secondary: #8b5cf6; /* violet-500 */
11
+ --success: #10b981; /* emerald-500 */
12
+ --danger: #ef4444; /* red-500 */
13
+ --warning: #f59e0b; /* amber-500 */
14
+ }
15
+
16
+ /* Base Styles */
17
  body {
18
+ font-family: 'Inter', sans-serif;
19
+ }
20
+
21
+ /* Glassmorphism Cards */
22
+ .glass-card {
23
+ background: rgba(30, 41, 59, 0.6); /* slate-800 with opacity */
24
+ backdrop-filter: blur(12px);
25
+ -webkit-backdrop-filter: blur(12px);
26
+ border: 1px solid rgba(148, 163, 184, 0.1); /* slate-400 with opacity */
27
+ box-shadow: 0 8px 32px rgba(2, 8, 20, 0.4);
28
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
29
+ }
30
+
31
+ .glass-card:hover {
32
+ border-color: rgba(148, 163, 184, 0.2);
33
+ box-shadow: 0 12px 40px rgba(2, 132, 199, 0.25); /* sky-600 with opacity */
34
+ transform: translateY(-2px);
35
+ }
36
+
37
+ /* Gradient Background */
38
+ .gradient-bg {
39
+ background: linear-gradient(135deg, rgba(2, 6, 23, 0.9) 0%, rgba(15, 23, 42, 0.9) 100%);
40
+ background-attachment: fixed;
41
+ }
42
+
43
+ /* Live Indicator Animation */
44
+ .live-indicator {
45
+ color: var(--success);
46
+ font-size: 0.75rem;
47
+ font-weight: 700;
48
+ letter-spacing: 0.1em;
49
+ }
50
+
51
+ .pulse-dot {
52
+ width: 8px;
53
+ height: 8px;
54
+ background: var(--success);
55
+ border-radius: 50%;
56
+ animation: pulse 2s ease-in-out infinite;
57
+ }
58
+
59
+ @keyframes pulse {
60
+ 0%, 100% { opacity: 1; transform: scale(1); }
61
+ 50% { opacity: 0.5; transform: scale(1.2); }
62
+ }
63
+
64
+ /* Custom Buttons */
65
+ .sky-button {
66
+ background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
67
+ color: white;
68
+ transition: all 0.3s ease;
69
+ position: relative;
70
+ overflow: hidden;
71
+ }
72
+
73
+ .sky-button::before {
74
+ content: '';
75
+ position: absolute;
76
+ top: 0;
77
+ left: -100%;
78
+ width: 100%;
79
+ height: 100%;
80
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
81
+ transition: left 0.6s;
82
+ }
83
+
84
+ .sky-button:hover::before {
85
+ left: 100%;
86
+ }
87
+
88
+ .sky-button:hover {
89
+ transform: translateY(-2px);
90
+ box-shadow: 0 10px 25px rgba(14, 165, 233, 0.4);
91
+ }
92
+
93
+ /* Status Badges */
94
+ .status-badge {
95
+ display: inline-flex;
96
+ align-items: center;
97
+ gap: 0.5rem;
98
+ padding: 0.25rem 0.75rem;
99
+ border-radius: 9999px;
100
+ font-size: 0.75rem;
101
+ font-weight: 600;
102
+ letter-spacing: 0.05em;
103
+ text-transform: uppercase;
104
+ }
105
+
106
+ .status-connected {
107
+ background: rgba(16, 185, 129, 0.15);
108
+ color: var(--success);
109
+ border: 1px solid rgba(16, 185, 129, 0.3);
110
  }
111
 
112
+ .status-disconnected {
113
+ background: rgba(239, 68, 68, 0.15);
114
+ color: var(--danger);
115
+ border: 1px solid rgba(239, 68, 68, 0.3);
116
  }
117
 
118
+ .status-pending {
119
+ background: rgba(245, 158, 11, 0.15);
120
+ color: var(--warning);
121
+ border: 1px solid rgba(245, 158, 11, 0.3);
 
122
  }
123
 
124
+ /* Scrollbar Styling */
125
+ ::-webkit-scrollbar {
126
+ width: 8px;
127
+ height: 8px;
 
 
128
  }
129
 
130
+ ::-webkit-scrollbar-track {
131
+ background: rgba(15, 23, 42, 0.5);
132
  }
133
+
134
+ ::-webkit-scrollbar-thumb {
135
+ background: var(--primary);
136
+ border-radius: 4px;
137
+ }
138
+
139
+ ::-webkit-scrollbar-thumb:hover {
140
+ background: var(--primary-dark);
141
+ }
142
+
143
+ /* Trading Signal Animation */
144
+ .signal-item {
145
+ animation: slideIn 0.5s cubic-bezier(0.4, 0, 0.2, 1);
146
+ border-left: 4px solid transparent;
147
+ transition: all 0.3s ease;
148
+ }
149
+
150
+ .signal-item.buy {
151
+ border-left-color: var(--success);
152
+ }
153
+
154
+ .signal-item.sell {
155
+ border-left-color: var(--danger);
156
+ }
157
+
158
+ @keyframes slideIn {
159
+ from {
160
+ opacity: 0;
161
+ transform: translateX(-20px);
162
+ }
163
+ to {
164
+ opacity: 1;
165
+ transform: translateX(0);
166
+ }
167
+ }
168
+
169
+ /* Exchange Status Card */
170
+ .exchange-status-item {
171
+ transition: transform 0.3s ease, box-shadow 0.3s ease;
172
+ }
173
+
174
+ .exchange-status-item:hover {
175
+ transform: translateX(5px);
176
+ box-shadow: -4px 0 20px rgba(14, 165, 233, 0.2);
177
+ }
178
+
179
+ /* Table Row Hover */
180
+ tbody tr {
181
+ transition: background-color 0.2s ease;
182
+ }
183
+
184
+ tbody tr:hover {
185
+ background: rgba(30, 41, 59, 0.8);
186
+ }
187
+
188
+ /* Feather Icon Transitions */
189
+ .feather {
190
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
191
+ }
192
+
193
+ /* Mobile Optimizations */
194
+ @media (max-width: 768px) {
195
+ .glass-card {
196
+ backdrop-filter: blur(8px);
197
+ }
198
+
199
+ .sky-button {
200
+ padding: 0.75rem 1rem;
201
+ }
202
+ }
203
+
204
+ /* Loading Skeleton */
205
+ .skeleton {
206
+ background: linear-gradient(90deg, rgba(30, 41, 59, 0.4) 25%, rgba(51, 65, 85, 0.6) 50%, rgba(30, 41, 59, 0.4) 75%);
207
+ background-size: 200% 100%;
208
+ animation: loading 1.5s infinite;
209
+ }
210
+
211
+ @keyframes loading {
212
+ 0% { background-position: 200% 0; }
213
+ 100% { background-position: -200% 0; }
214
+ }