Alvin3y1 commited on
Commit
2324f1b
Β·
verified Β·
1 Parent(s): 66a96ba

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +96 -60
app.py CHANGED
@@ -3,7 +3,6 @@ import json
3
  import logging
4
  import time
5
  import bisect
6
- import random
7
  from aiohttp import web
8
  import websockets
9
 
@@ -22,89 +21,116 @@ market_state = {
22
  "history": [],
23
  "current_mid": 0.0,
24
  "prev_mid": 0.0,
25
- "ready": False,
26
- "last_comment_time": 0
27
  }
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
39
 
40
- # 3. Logic Engine
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
 
76
  # --- HTML Frontend ---
77
  HTML_PAGE = f"""
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; }}
85
 
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
 
@@ -135,7 +161,7 @@ HTML_PAGE = f"""
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>
@@ -163,6 +189,7 @@ HTML_PAGE = f"""
163
  }};
164
 
165
  function addLog(data) {{
 
166
  if (data.comment.text === lastLogText) return;
167
  lastLogText = data.comment.text;
168
 
@@ -172,7 +199,8 @@ HTML_PAGE = f"""
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() {{
@@ -200,7 +228,7 @@ HTML_PAGE = f"""
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,
@@ -209,8 +237,16 @@ HTML_PAGE = f"""
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);
@@ -218,7 +254,7 @@ HTML_PAGE = f"""
218
  }} catch (e) {{ console.error("Fetch error:", e); }}
219
  }}
220
 
221
- setInterval(updateCharts, 750);
222
  </script>
223
  </body>
224
  </html>
@@ -317,7 +353,7 @@ async def handle_data(request):
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,
@@ -348,7 +384,7 @@ async def main():
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__":
 
3
  import logging
4
  import time
5
  import bisect
 
6
  from aiohttp import web
7
  import websockets
8
 
 
21
  "history": [],
22
  "current_mid": 0.0,
23
  "prev_mid": 0.0,
24
+ "ready": False
 
25
  }
26
 
27
  # --- AI Logic Helper ---
28
+ def generate_ai_commentary(diff_y):
29
+ """
30
+ Analyzes the shape of the Liquidity Curve (Bids - Asks).
31
+ Splits data into 'Near' (Close to price) and 'Deep' (Far from price).
32
+ """
33
+ if not diff_y or len(diff_y) < 10:
34
+ return {"text": "Gathering depth data...", "sentiment": "neutral"}
35
+
36
+ # 1. Split the data
37
+ # First 20% of steps = Near-term (Active trading zone)
38
+ # Last 20% of steps = Deep-term (Macro walls)
39
+ split_idx = int(len(diff_y) * 0.2)
40
+
41
+ near_data = diff_y[:split_idx]
42
+ deep_data = diff_y[-split_idx:]
43
 
44
+ near_avg = sum(near_data) / len(near_data)
45
+ deep_avg = sum(deep_data) / len(deep_data)
46
 
 
47
  msg = ""
48
  sentiment = "neutral"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
50
+ # --- PATTERN RECOGNITION ---
 
 
 
51
 
52
+ # 1. POSITIVE -> NEGATIVE (The "False Floor" or "Overhead Resistance")
53
+ if near_avg > 0 and deep_avg < 0:
54
+ sentiment = "warning"
55
+ msg = (
56
+ f"πŸ“‰ <b>STRUCTURAL FLIP (Pos ➝ Neg):</b><br>"
57
+ f"Near-term buyers are holding the price, BUT deeper liquidity reveals heavy sell pressure.<br>"
58
+ f"<i>Why?</i> Traders are defending the immediate level, but whales have placed large Ask walls higher up. "
59
+ f"Upside is capped; price may rally briefly then fail."
60
+ )
61
+
62
+ # 2. NEGATIVE -> POSITIVE (The "Bear Trap" or "Safety Net")
63
+ elif near_avg < 0 and deep_avg > 0:
64
+ sentiment = "bullish"
65
+ msg = (
66
+ f"πŸ“ˆ <b>STRUCTURAL FLIP (Neg ➝ Pos):</b><br>"
67
+ f"Immediate sell pressure is visible, BUT massive buy walls exist deeper down.<br>"
68
+ f"<i>Why?</i> Price is being suppressed locally, but smart money is waiting lower to absorb the dip. "
69
+ f"Downside is limited; this often precedes a bounce."
70
+ )
71
+
72
+ # 3. CONSISTENTLY POSITIVE (Full Bull)
73
+ elif near_avg > 0 and deep_avg > 0:
74
+ sentiment = "bullish"
75
+ strength = "Mild" if deep_avg < 50 else "Extreme"
76
+ msg = (
77
+ f"πŸš€ <b>FULL BULLISH CONVICTION:</b><br>"
78
+ f"Bids exceed Asks at both local and deep levels.<br>"
79
+ f"<i>Why?</i> There is no overhead supply. Buyers are aggressive at the current price AND stacking orders below. "
80
+ f"Path of least resistance is purely UP."
81
+ )
82
+
83
+ # 4. CONSISTENTLY NEGATIVE (Full Bear)
84
+ elif near_avg < 0 and deep_avg < 0:
85
+ sentiment = "bearish"
86
+ msg = (
87
+ f"πŸ”» <b>FULL BEARISH CONVICTION:</b><br>"
88
+ f"Asks exceed Bids at all levels.<br>"
89
+ f"<i>Why?</i> There is no support below. Sellers are active at the current price AND stacking orders higher. "
90
+ f"Price is likely to drift lower until buyers step in."
91
+ )
92
+
93
+ # 5. MIXED / CHOP
94
  else:
95
+ diff = near_avg - deep_avg
96
+ if abs(diff) < 5:
97
+ msg = "βš–οΈ <b>PERFECT BALANCE:</b> Liquidity is symmetrical. Market is waiting for a trigger."
98
  else:
99
+ msg = "πŸ”„ <b>TRANSITIONING:</b> Orderbook structure is shifting. Watch for a dominant side to emerge."
 
100
 
101
+ return {"text": msg, "sentiment": sentiment}
102
 
103
  # --- HTML Frontend ---
104
  HTML_PAGE = f"""
105
  <!DOCTYPE html>
106
  <html>
107
  <head>
108
+ <title>BTC-USD Structural AI</title>
109
  <script src="https://cdn.plot.ly/plotly-2.24.1.min.js"></script>
110
  <style>
111
  body {{ margin: 0; padding: 0; background-color: #0e0e0e; color: #ccc; font-family: 'Courier New', monospace; overflow: hidden; }}
112
 
 
113
  #container {{ display: flex; flex-direction: column; height: 100vh; width: 100vw; }}
114
 
115
+ /* Row 1: Charts */
116
  #row-top {{ flex: 1; display: flex; width: 100%; border-bottom: 1px solid #333; }}
117
 
118
+ /* Row 2: Charts + AI */
119
  #row-bot {{ flex: 1; display: flex; width: 100%; }}
120
 
121
  .col {{ width: 50%; height: 100%; border-right: 1px solid #333; position: relative; }}
122
+ .col-ai {{ width: 50%; height: 100%; background-color: #080808; display: flex; flex-direction: column; padding: 10px; overflow-y: auto; }}
123
 
124
+ /* AI Text Styling */
125
+ .terminal-header {{ color: #00bcd4; font-weight: bold; border-bottom: 1px dashed #333; padding-bottom: 5px; margin-bottom: 10px; font-size: 16px; }}
126
+ .log-entry {{ margin-bottom: 12px; font-size: 13px; border-left: 4px solid transparent; padding-left: 10px; background: #111; padding: 8px; border-radius: 4px; }}
127
+ .log-time {{ color: #555; font-size: 11px; display: block; margin-bottom: 4px; }}
128
 
129
  /* Sentiments */
130
+ .bullish {{ border-left-color: #00e676; }}
131
+ .bearish {{ border-left-color: #ff1744; }}
132
+ .neutral {{ border-left-color: #999; }}
133
+ .warning {{ border-left-color: #ff9800; }}
134
 
135
  .chart {{ width: 100%; height: 100%; }}
136
 
 
161
  </div>
162
  <div class="col-ai">
163
  <!-- AI TERMINAL -->
164
+ <div class="terminal-header">> DEPTH STRUCTURE ANALYSIS</div>
165
  <div id="terminal-logs"></div>
166
  </div>
167
  </div>
 
189
  }};
190
 
191
  function addLog(data) {{
192
+ // De-duplicate messages
193
  if (data.comment.text === lastLogText) return;
194
  lastLogText = data.comment.text;
195
 
 
199
  div.innerHTML = `<span class="log-time">${{timeStr}}</span> ${{data.comment.text}}`;
200
 
201
  termLogs.prepend(div);
202
+ // Keep history short
203
+ if (termLogs.children.length > 10) termLogs.removeChild(termLogs.lastChild);
204
  }}
205
 
206
  async function updateCharts() {{
 
228
  if (!initVol) {{ Plotly.newPlot(volDiv, tracesVol, {{ ...commonLayout, title: '<b>Cumulative Volume</b>', xaxis: {{title:'Distance ($)'}} }}, commonConfig); initVol = true; }}
229
  else {{ Plotly.react(volDiv, tracesVol, {{ ...commonLayout, title: '<b>Cumulative Volume</b>', xaxis: {{title:'Distance ($)'}} }}, commonConfig); }}
230
 
231
+ // 3. Net Difference (Bids - Asks)
232
  const traceDiff = {{
233
  x: data.diff.x,
234
  y: data.diff.y,
 
237
  fill: 'tozeroy',
238
  line: {{color: '#e040fb', width: 2}}
239
  }};
240
+ // Draw a zero line for reference
241
+ const layoutDiff = {{
242
+ ...commonLayout,
243
+ title: '<b>Net Liquidity (Bids - Asks)</b>',
244
+ xaxis: {{title:'Distance ($)'}},
245
+ shapes: [{{ type: 'line', x0: 0, x1: 1, xref: 'paper', y0: 0, y1: 0, line: {{color: '#666', width: 1, dash:'dot'}} }}]
246
+ }};
247
+
248
+ if (!initDiff) {{ Plotly.newPlot(diffDiv, [traceDiff], layoutDiff, commonConfig); initDiff = true; }}
249
+ else {{ Plotly.react(diffDiv, [traceDiff], layoutDiff, commonConfig); }}
250
 
251
  // 4. AI Log
252
  addLog(data);
 
254
  }} catch (e) {{ console.error("Fetch error:", e); }}
255
  }}
256
 
257
+ setInterval(updateCharts, 1000);
258
  </script>
259
  </body>
260
  </html>
 
353
  diff_y.append(val)
354
 
355
  # --- Generate AI Commentary ---
356
+ ai_output = generate_ai_commentary(diff_y)
357
 
358
  return web.json_response({
359
  "mid": mid,
 
384
  site = web.TCPSite(runner, '0.0.0.0', PORT)
385
  await site.start()
386
 
387
+ print(f"πŸš€ BTC-USD Deep Structure Dashboard: http://localhost:{PORT}")
388
  await asyncio.Event().wait()
389
 
390
  if __name__ == "__main__":