Spaces:
Running
Running
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- README.md +8 -5
- components/navbar.js +117 -0
- components/sidebar.js +180 -0
- index.html +154 -19
- script.js +228 -0
- style.css +204 -18
README.md
CHANGED
|
@@ -1,10 +1,13 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
|
|
|
|
|
|
| 8 |
---
|
| 9 |
|
| 10 |
-
|
|
|
|
|
|
| 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 |
-
<!
|
| 2 |
-
<html>
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
}
|
| 5 |
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
|
|
|
| 9 |
}
|
| 10 |
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
margin-top: 5px;
|
| 16 |
}
|
| 17 |
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
border: 1px solid lightgray;
|
| 23 |
-
border-radius: 16px;
|
| 24 |
}
|
| 25 |
|
| 26 |
-
|
| 27 |
-
|
| 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 |
+
}
|