Alvin3y1 commited on
Commit
66a96ba
Β·
verified Β·
1 Parent(s): 74c1714

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +79 -73
app.py CHANGED
@@ -28,16 +28,11 @@ market_state = {
28
 
29
  # --- AI Logic Helper ---
30
  def generate_ai_commentary(diff_y, mid, prev_mid):
31
- """
32
- Analyzes the Net Liquidity (diff_y) and Price Action to generate commentary.
33
- diff_y is a list of (BidVol - AskVol) at increasing distances.
34
- """
35
  if not diff_y:
36
- return {"text": "Initializing analysis...", "sentiment": "neutral"}
37
 
38
  # 1. Calculate Aggregates
39
  net_total = diff_y[-1] # Total Net Liquidity at max depth
40
- avg_liquidity = sum(diff_y) / len(diff_y)
41
 
42
  # 2. Price Trend
43
  price_delta = mid - prev_mid
@@ -46,37 +41,35 @@ def generate_ai_commentary(diff_y, mid, prev_mid):
46
  msg = ""
47
  sentiment = "neutral"
48
 
49
- # -- SCENARIO 1: STRONG DIRECTIONAL --
50
  if net_total > 50:
51
  sentiment = "bullish"
52
- msg = f"πŸš€ <b>STRONG BUY SUPPORT:</b> Net surplus of {int(net_total)} BTC. Orderbook is heavily tilted towards Bids."
53
  elif net_total < -50:
54
  sentiment = "bearish"
55
- msg = f"πŸ“‰ <b>HEAVY SELL PRESSURE:</b> Net deficit of {int(net_total)} BTC. Sellers are dominating the book."
56
 
57
- # -- SCENARIO 2: ABSORPTION / DIVERGENCE --
58
- # Price dropping, but Orderbook is Bullish (Bids absorbing sells)
59
- elif price_delta < 0 and net_total > 20:
60
  sentiment = "warning"
61
- msg = f"πŸ›‘οΈ <b>ABSORPTION DETECTED:</b> Price is falling, but Bid depth is increasing (+{int(net_total)} BTC). Passive buyers are catching the dump."
62
-
63
- # Price rising, but Orderbook is Bearish (Asks absorbing buys)
64
- elif price_delta > 0 and net_total < -20:
65
  sentiment = "warning"
66
- msg = f"🧱 <b>HIDDEN WALL:</b> Price is rising into heavy Sell liquidity ({int(net_total)} BTC diff). Breakout might fail."
67
 
68
- # -- SCENARIO 3: EQUILIBRIUM --
69
  elif abs(net_total) < 10:
70
  sentiment = "neutral"
71
- msg = f"βš–οΈ <b>EQUILIBRIUM:</b> Bids and Asks are perfectly balanced. Expect low volatility or a sudden breakout."
72
 
73
  # -- SCENARIO 4: MOMENTUM --
74
  else:
75
  if net_total > 0:
76
- msg = f"πŸ“ˆ <b>Bullish Bias:</b> Moderate buy support (+{int(net_total)} BTC). Path of least resistance is UP."
77
  sentiment = "bullish"
78
  else:
79
- msg = f"πŸ“‰ <b>Bearish Bias:</b> Moderate sell overhang ({int(net_total)} BTC). Path of least resistance is DOWN."
 
80
 
81
  return {"text": msg, "sentiment": sentiment, "net": net_total}
82
 
@@ -85,7 +78,7 @@ HTML_PAGE = f"""
85
  <!DOCTYPE html>
86
  <html>
87
  <head>
88
- <title>BTC-USD AI Analyst</title>
89
  <script src="https://cdn.plot.ly/plotly-2.24.1.min.js"></script>
90
  <style>
91
  body {{ margin: 0; padding: 0; background-color: #0e0e0e; color: #ccc; font-family: 'Courier New', monospace; overflow: hidden; }}
@@ -93,28 +86,26 @@ HTML_PAGE = f"""
93
  /* Layout Grid */
94
  #container {{ display: flex; flex-direction: column; height: 100vh; width: 100vw; }}
95
 
96
- /* Row 1: Charts (60% Height) */
97
- #row-charts {{ flex: 6; display: flex; width: 100%; border-bottom: 2px solid #333; }}
98
- .col-chart {{ width: 50%; height: 100%; border-right: 1px solid #333; }}
99
 
100
- /* Row 2: AI Terminal (40% Height) */
101
- #row-terminal {{ flex: 4; display: flex; flex-direction: column; background-color: #050505; padding: 10px; overflow-y: auto; }}
102
 
 
 
 
103
  /* Terminal Styling */
104
  .terminal-header {{ color: #00bcd4; font-weight: bold; border-bottom: 1px dashed #333; padding-bottom: 5px; margin-bottom: 10px; }}
105
- .log-entry {{ margin-bottom: 6px; font-size: 14px; line-height: 1.4; border-left: 3px solid transparent; padding-left: 8px; }}
106
- .log-time {{ color: #666; font-size: 12px; margin-right: 10px; }}
107
 
108
- /* Sentiment Colors */
109
  .bullish {{ border-left-color: #00e676; color: #e8f5e9; }}
110
  .bearish {{ border-left-color: #ff1744; color: #ffebee; }}
111
  .neutral {{ border-left-color: #999; color: #ccc; }}
112
  .warning {{ border-left-color: #ff9800; color: #fff3e0; }}
113
 
114
- /* Highlight classes for inner HTML */
115
- b {{ font-weight: bold; }}
116
-
117
- /* Charts fill their containers */
118
  .chart {{ width: 100%; height: 100%; }}
119
 
120
  #status {{ position: absolute; top: 10px; left: 60px; z-index: 100; font-size: 14px; background: rgba(0,0,0,0.8); padding: 5px 10px; border-radius: 4px; border: 1px solid #333; }}
@@ -123,33 +114,41 @@ HTML_PAGE = f"""
123
  </style>
124
  </head>
125
  <body>
126
- <div id="status">Connecting to Neural Net...</div>
127
 
128
  <div id="container">
129
- <!-- ROW 1: CONTEXT CHARTS -->
130
- <div id="row-charts">
131
- <div class="col-chart">
132
  <div id="price-chart" class="chart"></div>
133
  </div>
134
- <div class="col-chart">
135
  <div id="vol-chart" class="chart"></div>
136
  </div>
137
  </div>
138
 
139
- <!-- ROW 2: AI COMMENTATOR -->
140
- <div id="row-terminal">
141
- <div class="terminal-header">> AI MARKET ANALYST (Based on Net Liquidity)</div>
142
- <div id="terminal-logs"></div>
 
 
 
 
 
 
 
143
  </div>
144
  </div>
145
 
146
  <script>
147
  const priceDiv = document.getElementById('price-chart');
148
  const volDiv = document.getElementById('vol-chart');
 
149
  const termLogs = document.getElementById('terminal-logs');
150
  const statusDiv = document.getElementById('status');
151
 
152
- let initPrice = false, initVol = false;
153
  let lastLogText = "";
154
 
155
  const commonConfig = {{ responsive: true, displayModeBar: false }};
@@ -157,30 +156,23 @@ HTML_PAGE = f"""
157
  paper_bgcolor: '#0e0e0e',
158
  plot_bgcolor: '#0e0e0e',
159
  font: {{ color: '#aaa', family: 'Courier New' }},
160
- margin: {{ t: 30, b: 25, l: 40, r: 20 }},
161
  showlegend: false,
162
  xaxis: {{ gridcolor: '#222' }},
163
  yaxis: {{ gridcolor: '#222' }}
164
  }};
165
 
166
  function addLog(data) {{
167
- // Prevent spamming the exact same message
168
  if (data.comment.text === lastLogText) return;
169
  lastLogText = data.comment.text;
170
 
171
  const div = document.createElement('div');
172
  div.className = `log-entry ${{data.comment.sentiment}}`;
173
-
174
  const timeStr = new Date().toLocaleTimeString();
175
- div.innerHTML = `<span class="log-time">[${{timeStr}}]</span> ${{data.comment.text}}`;
176
 
177
- // Insert at top
178
  termLogs.prepend(div);
179
-
180
- // Keep max 20 logs
181
- if (termLogs.children.length > 20) {{
182
- termLogs.removeChild(termLogs.lastChild);
183
- }}
184
  }}
185
 
186
  async function updateCharts() {{
@@ -193,29 +185,40 @@ HTML_PAGE = f"""
193
  return;
194
  }}
195
 
196
- // Update Status
197
- statusDiv.innerHTML = `Mid: <span class="${{data.mid >= data.prev_mid ? 'green' : 'red'}}">$${{data.mid.toLocaleString(undefined, {{minimumFractionDigits: 2}})}}</span> | Net Liq: ${{data.comment.net.toFixed(2)}} BTC`;
198
 
199
- // 1. PRICE CHART
200
- const tracePrice = {{ x: data.history.map(d=>new Date(d.t*1000)), y: data.history.map(d=>d.p), type: 'scatter', mode:'lines', line: {{color: '#29b6f6', width: 2}} }};
201
  if (!initPrice) {{ Plotly.newPlot(priceDiv, [tracePrice], {{ ...commonLayout, title: '<b>Midprice</b>', xaxis: {{type:'date', gridcolor:'#222'}} }}, commonConfig); initPrice = true; }}
202
  else {{ Plotly.react(priceDiv, [tracePrice], {{ ...commonLayout, title: '<b>Midprice</b>', xaxis: {{type:'date', gridcolor:'#222'}} }}, commonConfig); }}
203
 
204
- // 2. VOLUME CHART
205
  const tracesVol = [
206
- {{ x: data.vol.dist_bids, y: data.vol.vol_bids, type: 'scatter', name: 'Bids', line: {{color: '#00e676'}} }},
207
- {{ x: data.vol.dist_asks, y: data.vol.vol_asks, type: 'scatter', name: 'Asks', line: {{color: '#ff1744'}} }}
208
  ];
209
- if (!initVol) {{ Plotly.newPlot(volDiv, tracesVol, {{ ...commonLayout, title: '<b>Cumulative Volume by Distance</b>', xaxis: {{title:'Distance ($)'}} }}, commonConfig); initVol = true; }}
210
- else {{ Plotly.react(volDiv, tracesVol, {{ ...commonLayout, title: '<b>Cumulative Volume by Distance</b>', xaxis: {{title:'Distance ($)'}} }}, commonConfig); }}
211
-
212
- // 3. AI COMMENTARY LOG
 
 
 
 
 
 
 
 
 
 
 
 
213
  addLog(data);
214
 
215
  }} catch (e) {{ console.error("Fetch error:", e); }}
216
  }}
217
 
218
- setInterval(updateCharts, 750); // Slower update for readability
219
  </script>
220
  </body>
221
  </html>
@@ -294,13 +297,13 @@ async def handle_data(request):
294
  cum += q
295
  d_a_x.append(d); d_a_y.append(cum)
296
 
297
- # --- Calculate Net Liquidity Array for AI ---
298
- diff_values = []
299
 
300
  if d_b_x and d_a_x:
301
  max_dist = min(d_b_x[-1], d_a_x[-1])
302
- step_size = max_dist / 50 # 50 Sampling points for AI
303
- steps = [i * step_size for i in range(1, 51)]
304
 
305
  for s in steps:
306
  idx_b = bisect.bisect_right(d_b_x, s)
@@ -309,15 +312,18 @@ async def handle_data(request):
309
  idx_a = bisect.bisect_right(d_a_x, s)
310
  vol_a = d_a_y[idx_a-1] if idx_a > 0 else 0
311
 
312
- diff_values.append(vol_b - vol_a)
 
 
313
 
314
  # --- Generate AI Commentary ---
315
- ai_output = generate_ai_commentary(diff_values, mid, market_state['prev_mid'])
316
 
317
  return web.json_response({
318
  "mid": mid,
319
  "prev_mid": market_state['prev_mid'],
320
  "vol": { "dist_bids": d_b_x, "vol_bids": d_b_y, "dist_asks": d_a_x, "vol_asks": d_a_y },
 
321
  "comment": ai_output,
322
  "history": market_state['history']
323
  })
@@ -342,7 +348,7 @@ async def main():
342
  site = web.TCPSite(runner, '0.0.0.0', PORT)
343
  await site.start()
344
 
345
- print(f"πŸš€ BTC-USD AI Dashboard: http://localhost:{PORT}")
346
  await asyncio.Event().wait()
347
 
348
  if __name__ == "__main__":
 
28
 
29
  # --- AI Logic Helper ---
30
  def generate_ai_commentary(diff_y, mid, prev_mid):
 
 
 
 
31
  if not diff_y:
32
+ return {"text": "Initializing analysis...", "sentiment": "neutral", "net": 0}
33
 
34
  # 1. Calculate Aggregates
35
  net_total = diff_y[-1] # Total Net Liquidity at max depth
 
36
 
37
  # 2. Price Trend
38
  price_delta = mid - prev_mid
 
41
  msg = ""
42
  sentiment = "neutral"
43
 
44
+ # -- SCENARIO 1: EXTREME IMBALANCE --
45
  if net_total > 50:
46
  sentiment = "bullish"
47
+ msg = f"πŸš€ <b>STRONG BUY WALL:</b> Net surplus of {int(net_total)} BTC. Orderbook tilted heavily to Bids."
48
  elif net_total < -50:
49
  sentiment = "bearish"
50
+ msg = f"πŸ“‰ <b>HEAVY SELL WALL:</b> Net deficit of {int(net_total)} BTC. Sellers dominating."
51
 
52
+ # -- SCENARIO 2: ABSORPTION (Price moving vs Liquidity) --
53
+ elif price_delta < -5 and net_total > 20:
 
54
  sentiment = "warning"
55
+ msg = f"πŸ›‘οΈ <b>ABSORPTION:</b> Price dropping, but Buyers are stepping in (+{int(net_total)} BTC surplus)."
56
+ elif price_delta > 5 and net_total < -20:
 
 
57
  sentiment = "warning"
58
+ msg = f"🧱 <b>RESISTANCE:</b> Price rising into Sell liquidity ({int(net_total)} BTC deficit)."
59
 
60
+ # -- SCENARIO 3: CHOP / EQUILIBRIUM --
61
  elif abs(net_total) < 10:
62
  sentiment = "neutral"
63
+ msg = f"βš–οΈ <b>EQUILIBRIUM:</b> Liquidity is balanced. Waiting for a breakout trigger."
64
 
65
  # -- SCENARIO 4: MOMENTUM --
66
  else:
67
  if net_total > 0:
68
+ msg = f"πŸ“ˆ <b>Bullish Bias:</b> Moderate buy support (+{int(net_total)} BTC)."
69
  sentiment = "bullish"
70
  else:
71
+ msg = f"πŸ“‰ <b>Bearish Bias:</b> Moderate sell pressure ({int(net_total)} BTC)."
72
+ sentiment = "bearish"
73
 
74
  return {"text": msg, "sentiment": sentiment, "net": net_total}
75
 
 
78
  <!DOCTYPE html>
79
  <html>
80
  <head>
81
+ <title>BTC-USD AI Hybrid Dashboard</title>
82
  <script src="https://cdn.plot.ly/plotly-2.24.1.min.js"></script>
83
  <style>
84
  body {{ margin: 0; padding: 0; background-color: #0e0e0e; color: #ccc; font-family: 'Courier New', monospace; overflow: hidden; }}
 
86
  /* Layout Grid */
87
  #container {{ display: flex; flex-direction: column; height: 100vh; width: 100vw; }}
88
 
89
+ /* Row 1: Price & Vol */
90
+ #row-top {{ flex: 1; display: flex; width: 100%; border-bottom: 1px solid #333; }}
 
91
 
92
+ /* Row 2: Diff & AI */
93
+ #row-bot {{ flex: 1; display: flex; width: 100%; }}
94
 
95
+ .col {{ width: 50%; height: 100%; border-right: 1px solid #333; position: relative; }}
96
+ .col-ai {{ width: 50%; height: 100%; background-color: #050505; display: flex; flex-direction: column; padding: 10px; overflow-y: auto; }}
97
+
98
  /* Terminal Styling */
99
  .terminal-header {{ color: #00bcd4; font-weight: bold; border-bottom: 1px dashed #333; padding-bottom: 5px; margin-bottom: 10px; }}
100
+ .log-entry {{ margin-bottom: 8px; font-size: 13px; border-left: 3px solid transparent; padding-left: 8px; }}
101
+ .log-time {{ color: #555; font-size: 11px; margin-right: 8px; }}
102
 
103
+ /* Sentiments */
104
  .bullish {{ border-left-color: #00e676; color: #e8f5e9; }}
105
  .bearish {{ border-left-color: #ff1744; color: #ffebee; }}
106
  .neutral {{ border-left-color: #999; color: #ccc; }}
107
  .warning {{ border-left-color: #ff9800; color: #fff3e0; }}
108
 
 
 
 
 
109
  .chart {{ width: 100%; height: 100%; }}
110
 
111
  #status {{ position: absolute; top: 10px; left: 60px; z-index: 100; font-size: 14px; background: rgba(0,0,0,0.8); padding: 5px 10px; border-radius: 4px; border: 1px solid #333; }}
 
114
  </style>
115
  </head>
116
  <body>
117
+ <div id="status">Connecting...</div>
118
 
119
  <div id="container">
120
+ <!-- ROW 1 -->
121
+ <div id="row-top">
122
+ <div class="col">
123
  <div id="price-chart" class="chart"></div>
124
  </div>
125
+ <div class="col">
126
  <div id="vol-chart" class="chart"></div>
127
  </div>
128
  </div>
129
 
130
+ <!-- ROW 2 -->
131
+ <div id="row-bot">
132
+ <div class="col">
133
+ <!-- NET DIFFERENCE CHART -->
134
+ <div id="diff-chart" class="chart"></div>
135
+ </div>
136
+ <div class="col-ai">
137
+ <!-- AI TERMINAL -->
138
+ <div class="terminal-header">> AI MARKET COMMENTARY</div>
139
+ <div id="terminal-logs"></div>
140
+ </div>
141
  </div>
142
  </div>
143
 
144
  <script>
145
  const priceDiv = document.getElementById('price-chart');
146
  const volDiv = document.getElementById('vol-chart');
147
+ const diffDiv = document.getElementById('diff-chart');
148
  const termLogs = document.getElementById('terminal-logs');
149
  const statusDiv = document.getElementById('status');
150
 
151
+ let initPrice = false, initVol = false, initDiff = false;
152
  let lastLogText = "";
153
 
154
  const commonConfig = {{ responsive: true, displayModeBar: false }};
 
156
  paper_bgcolor: '#0e0e0e',
157
  plot_bgcolor: '#0e0e0e',
158
  font: {{ color: '#aaa', family: 'Courier New' }},
159
+ margin: {{ t: 30, b: 25, l: 45, r: 20 }},
160
  showlegend: false,
161
  xaxis: {{ gridcolor: '#222' }},
162
  yaxis: {{ gridcolor: '#222' }}
163
  }};
164
 
165
  function addLog(data) {{
 
166
  if (data.comment.text === lastLogText) return;
167
  lastLogText = data.comment.text;
168
 
169
  const div = document.createElement('div');
170
  div.className = `log-entry ${{data.comment.sentiment}}`;
 
171
  const timeStr = new Date().toLocaleTimeString();
172
+ div.innerHTML = `<span class="log-time">${{timeStr}}</span> ${{data.comment.text}}`;
173
 
 
174
  termLogs.prepend(div);
175
+ if (termLogs.children.length > 25) termLogs.removeChild(termLogs.lastChild);
 
 
 
 
176
  }}
177
 
178
  async function updateCharts() {{
 
185
  return;
186
  }}
187
 
188
+ statusDiv.innerHTML = `Mid: <span class="${{data.mid >= data.prev_mid ? 'green' : 'red'}}">$${{data.mid.toLocaleString(undefined, {{minimumFractionDigits: 2}})}}</span>`;
 
189
 
190
+ // 1. Price
191
+ const tracePrice = {{ x: data.history.map(d=>new Date(d.t*1000)), y: data.history.map(d=>d.p), type: 'scatter', mode:'lines', line: {{color: '#29b6f6'}} }};
192
  if (!initPrice) {{ Plotly.newPlot(priceDiv, [tracePrice], {{ ...commonLayout, title: '<b>Midprice</b>', xaxis: {{type:'date', gridcolor:'#222'}} }}, commonConfig); initPrice = true; }}
193
  else {{ Plotly.react(priceDiv, [tracePrice], {{ ...commonLayout, title: '<b>Midprice</b>', xaxis: {{type:'date', gridcolor:'#222'}} }}, commonConfig); }}
194
 
195
+ // 2. Volume
196
  const tracesVol = [
197
+ {{ x: data.vol.dist_bids, y: data.vol.vol_bids, type: 'scatter', name: 'Bid', line: {{color: '#00e676'}} }},
198
+ {{ x: data.vol.dist_asks, y: data.vol.vol_asks, type: 'scatter', name: 'Ask', line: {{color: '#ff1744'}} }}
199
  ];
200
+ if (!initVol) {{ Plotly.newPlot(volDiv, tracesVol, {{ ...commonLayout, title: '<b>Cumulative Volume</b>', xaxis: {{title:'Distance ($)'}} }}, commonConfig); initVol = true; }}
201
+ else {{ Plotly.react(volDiv, tracesVol, {{ ...commonLayout, title: '<b>Cumulative Volume</b>', xaxis: {{title:'Distance ($)'}} }}, commonConfig); }}
202
+
203
+ // 3. Net Difference (Restored)
204
+ const traceDiff = {{
205
+ x: data.diff.x,
206
+ y: data.diff.y,
207
+ type: 'scatter',
208
+ mode: 'lines',
209
+ fill: 'tozeroy',
210
+ line: {{color: '#e040fb', width: 2}}
211
+ }};
212
+ if (!initDiff) {{ Plotly.newPlot(diffDiv, [traceDiff], {{ ...commonLayout, title: '<b>Net Liquidity (Bids - Asks)</b>', xaxis: {{title:'Distance ($)'}} }}, commonConfig); initDiff = true; }}
213
+ else {{ Plotly.react(diffDiv, [traceDiff], {{ ...commonLayout, title: '<b>Net Liquidity (Bids - Asks)</b>', xaxis: {{title:'Distance ($)'}} }}, commonConfig); }}
214
+
215
+ // 4. AI Log
216
  addLog(data);
217
 
218
  }} catch (e) {{ console.error("Fetch error:", e); }}
219
  }}
220
 
221
+ setInterval(updateCharts, 750);
222
  </script>
223
  </body>
224
  </html>
 
297
  cum += q
298
  d_a_x.append(d); d_a_y.append(cum)
299
 
300
+ # --- Calculate Net Liquidity Array (Diff) ---
301
+ diff_x, diff_y = [], []
302
 
303
  if d_b_x and d_a_x:
304
  max_dist = min(d_b_x[-1], d_a_x[-1])
305
+ step_size = max_dist / 100
306
+ steps = [i * step_size for i in range(1, 101)]
307
 
308
  for s in steps:
309
  idx_b = bisect.bisect_right(d_b_x, s)
 
312
  idx_a = bisect.bisect_right(d_a_x, s)
313
  vol_a = d_a_y[idx_a-1] if idx_a > 0 else 0
314
 
315
+ val = vol_b - vol_a
316
+ diff_x.append(s)
317
+ diff_y.append(val)
318
 
319
  # --- Generate AI Commentary ---
320
+ ai_output = generate_ai_commentary(diff_y, mid, market_state['prev_mid'])
321
 
322
  return web.json_response({
323
  "mid": mid,
324
  "prev_mid": market_state['prev_mid'],
325
  "vol": { "dist_bids": d_b_x, "vol_bids": d_b_y, "dist_asks": d_a_x, "vol_asks": d_a_y },
326
+ "diff": { "x": diff_x, "y": diff_y },
327
  "comment": ai_output,
328
  "history": market_state['history']
329
  })
 
348
  site = web.TCPSite(runner, '0.0.0.0', PORT)
349
  await site.start()
350
 
351
+ print(f"πŸš€ BTC-USD AI+Graph Dashboard: http://localhost:{PORT}")
352
  await asyncio.Event().wait()
353
 
354
  if __name__ == "__main__":