Alvin3y1 commited on
Commit
8aefbf1
Β·
verified Β·
1 Parent(s): d702b3f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +66 -62
app.py CHANGED
@@ -28,29 +28,22 @@ HTML_PAGE = f"""
28
  <!DOCTYPE html>
29
  <html>
30
  <head>
31
- <title>BTC-USD 5-Layer Analysis</title>
32
  <script src="https://cdn.plot.ly/plotly-2.24.1.min.js"></script>
33
  <style>
34
  body {{ margin: 0; padding: 0; background-color: #0e0e0e; color: #ccc; font-family: sans-serif; overflow: hidden; }}
35
 
36
- /* Layout Grid - 3 Rows */
37
  #container {{ display: flex; flex-direction: column; height: 100vh; width: 100vw; }}
38
-
39
- /* Each Row takes 33% height */
40
  .row {{ flex: 1; display: flex; width: 100%; border-bottom: 1px solid #333; }}
41
-
42
- /* Columns */
43
  .col-left {{ width: 50%; border-right: 1px solid #333; position: relative; }}
44
  .col-right {{ width: 50%; position: relative; }}
45
  .col-full {{ width: 100%; position: relative; }}
46
-
47
- /* Charts fill their containers */
48
  .chart {{ width: 100%; height: 100%; }}
49
 
50
- /* Status Badge */
51
- #status {{ position: absolute; top: 10px; left: 60px; z-index: 100; font-size: 14px; background: rgba(0,0,0,0.7); padding: 5px 10px; border-radius: 4px; pointer-events: none; border: 1px solid #333; }}
52
  .green {{ color: #00e676; }}
53
  .red {{ color: #ff1744; }}
 
54
  </style>
55
  </head>
56
  <body>
@@ -77,7 +70,7 @@ HTML_PAGE = f"""
77
  </div>
78
  </div>
79
 
80
- <!-- ROW 3: Integration (New) -->
81
  <div class="row">
82
  <div class="col-full">
83
  <div id="integral-chart" class="chart"></div>
@@ -91,11 +84,9 @@ HTML_PAGE = f"""
91
  const volDiv = document.getElementById('vol-chart');
92
  const diffDiv = document.getElementById('diff-chart');
93
  const intDiv = document.getElementById('integral-chart');
94
-
95
  const statusDiv = document.getElementById('status');
96
 
97
- // Init Flags
98
- let initPrice = false, initImbP = false, initVol = false, initDiff = false, initInt = false;
99
 
100
  const commonConfig = {{ responsive: true, displayModeBar: false }};
101
  const commonLayout = {{
@@ -113,50 +104,51 @@ HTML_PAGE = f"""
113
  const res = await fetch('/data');
114
  const data = await res.json();
115
 
116
- if (data.error) {{
117
- statusDiv.innerHTML = "Waiting for data...";
118
- return;
119
- }}
120
-
121
- statusDiv.innerHTML = `Mid: <span class="${{data.mid >= data.prev_mid ? 'green' : 'red'}}">$${{data.mid.toLocaleString(undefined, {{minimumFractionDigits: 2}})}}</span> | Integral Trend: ${{data.integral.last_val ? data.integral.last_val.toFixed(2) : 0}}`;
122
-
123
- // 1. PRICE HISTORY
124
- if (!initPrice) {{
125
- Plotly.newPlot(priceDiv, [{{ 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}} }}],
126
- {{ ...commonLayout, title: '<b>Midprice</b>', xaxis: {{type:'date', gridcolor:'#222'}} }}, commonConfig);
127
- initPrice = true;
128
- }} else {{
129
- Plotly.react(priceDiv, [{{ 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}} }}],
130
- {{ ...commonLayout, title: '<b>Midprice</b>', xaxis: {{type:'date', gridcolor:'#222'}} }}, commonConfig);
131
- }}
132
-
133
- // 2. IMBALANCE %
134
- const layoutImbP = {{ ...commonLayout, title: '<b>Pressure %</b>', yaxis: {{range: [-105, 105], gridcolor:'#222'}} }};
135
- if (!initImbP) {{ Plotly.newPlot(imbPercentDiv, [{{ x: data.imbalance_pct.x, y: data.imbalance_pct.y, type: 'scatter', mode: 'lines', fill: 'tozeroy', line: {{color: '#ffeb3b'}} }}], layoutImbP, commonConfig); initImbP = true; }}
136
- else {{ Plotly.react(imbPercentDiv, [{{ x: data.imbalance_pct.x, y: data.imbalance_pct.y, type: 'scatter', mode: 'lines', fill: 'tozeroy', line: {{color: '#ffeb3b'}} }}], layoutImbP, commonConfig); }}
137
-
138
- // 3. VOLUME BY DISTANCE
139
- const layoutVol = {{ ...commonLayout, title: '<b>Volume</b>' }};
140
- const tracesVol = [
141
- {{ x: data.imbalance_vol.dist_bids, y: data.imbalance_vol.vol_bids, type: 'scatter', name: 'Bid', line: {{color: '#00e676'}} }},
142
- {{ x: data.imbalance_vol.dist_asks, y: data.imbalance_vol.vol_asks, type: 'scatter', name: 'Ask', line: {{color: '#ff1744'}} }}
143
- ];
144
- if (!initVol) {{ Plotly.newPlot(volDiv, tracesVol, layoutVol, commonConfig); initVol = true; }}
145
- else {{ Plotly.react(volDiv, tracesVol, layoutVol, commonConfig); }}
 
 
 
 
 
 
146
 
147
  // 4. NET DIFF
148
- const layoutDiff = {{ ...commonLayout, title: '<b>Net Diff (Bids - Asks)</b>' }};
149
- const traceDiff = {{ x: data.diff.x, y: data.diff.y, type: 'scatter', mode: 'lines', fill: 'tozeroy', line: {{color: '#00bcd4'}} }};
150
- if (!initDiff) {{ Plotly.newPlot(diffDiv, [traceDiff], layoutDiff, commonConfig); initDiff = true; }}
151
- else {{ Plotly.react(diffDiv, [traceDiff], layoutDiff, commonConfig); }}
152
-
153
- // 5. INTEGRAL OF DIFF (New)
154
- const layoutInt = {{ ...commonLayout, title: '<b>Integrated Net Liquidity (Structural Trend)</b>' }};
155
- const intColor = (data.integral.last_val >= 0) ? '#e040fb' : '#e040fb';
156
- const traceInt = {{ x: data.integral.x, y: data.integral.y, type: 'scatter', mode: 'lines', fill: 'tozeroy', line: {{color: intColor}} }};
157
-
158
- if (!initInt) {{ Plotly.newPlot(intDiv, [traceInt], layoutInt, commonConfig); initInt = true; }}
159
- else {{ Plotly.react(intDiv, [traceInt], layoutInt, commonConfig); }}
160
 
161
  }} catch (e) {{ console.error("Fetch error:", e); }}
162
  }}
@@ -220,11 +212,11 @@ async def handle_data(request):
220
 
221
  mid = market_state['current_mid']
222
 
223
- # --- Raw Data ---
224
  raw_bids = sorted(market_state['bids'].items(), key=lambda x: -x[0])[:300]
225
  raw_asks = sorted(market_state['asks'].items(), key=lambda x: x[0])[:300]
226
 
227
- # --- Distance Data ---
228
  dist_bids = [(mid - p, q) for p, q in raw_bids if mid - p >= 0]
229
  d_b_x, d_b_y = [], []
230
  cum_d = 0
@@ -244,14 +236,15 @@ async def handle_data(request):
244
  diff_x, diff_y = [], []
245
  int_x, int_y = [], []
246
  running_int = 0
 
247
 
248
  if d_b_x and d_a_x:
249
  max_dist = min(d_b_x[-1], d_a_x[-1])
250
  step_size = max_dist / 100
251
  steps = [i * step_size for i in range(1, 101)]
252
 
253
- for s in steps:
254
- # 1. Get Volumes
255
  idx_b = bisect.bisect_right(d_b_x, s)
256
  vol_b = d_b_y[idx_b-1] if idx_b > 0 else 0
257
 
@@ -269,14 +262,25 @@ async def handle_data(request):
269
  diff_x.append(s)
270
  diff_y.append(diff)
271
 
272
- # 4. Integral of Diff
273
  running_int += diff
274
  int_x.append(s)
275
  int_y.append(running_int)
 
 
 
 
 
 
 
 
 
 
276
 
277
  return web.json_response({
278
  "mid": mid,
279
  "prev_mid": market_state['history'][-2]['p'] if len(market_state['history']) > 1 else mid,
 
280
  "imbalance_vol": { "dist_bids": d_b_x, "vol_bids": d_b_y, "dist_asks": d_a_x, "vol_asks": d_a_y },
281
  "imbalance_pct": { "x": imb_x, "y": imb_y },
282
  "diff": { "x": diff_x, "y": diff_y },
@@ -304,7 +308,7 @@ async def main():
304
  site = web.TCPSite(runner, '0.0.0.0', PORT)
305
  await site.start()
306
 
307
- print(f"πŸš€ BTC-USD 5-Layer Dashboard: http://localhost:{PORT}")
308
  await asyncio.Event().wait()
309
 
310
  if __name__ == "__main__":
 
28
  <!DOCTYPE html>
29
  <html>
30
  <head>
31
+ <title>BTC-USD Wall Sharpness</title>
32
  <script src="https://cdn.plot.ly/plotly-2.24.1.min.js"></script>
33
  <style>
34
  body {{ margin: 0; padding: 0; background-color: #0e0e0e; color: #ccc; font-family: sans-serif; overflow: hidden; }}
35
 
 
36
  #container {{ display: flex; flex-direction: column; height: 100vh; width: 100vw; }}
 
 
37
  .row {{ flex: 1; display: flex; width: 100%; border-bottom: 1px solid #333; }}
 
 
38
  .col-left {{ width: 50%; border-right: 1px solid #333; position: relative; }}
39
  .col-right {{ width: 50%; position: relative; }}
40
  .col-full {{ width: 100%; position: relative; }}
 
 
41
  .chart {{ width: 100%; height: 100%; }}
42
 
43
+ #status {{ position: absolute; top: 10px; left: 60px; z-index: 100; font-size: 14px; background: rgba(0,0,0,0.8); padding: 8px 12px; border-radius: 4px; pointer-events: none; border: 1px solid #333; box-shadow: 0 0 10px rgba(0,0,0,0.5); }}
 
44
  .green {{ color: #00e676; }}
45
  .red {{ color: #ff1744; }}
46
+ .white {{ color: #fff; font-weight: bold; }}
47
  </style>
48
  </head>
49
  <body>
 
70
  </div>
71
  </div>
72
 
73
+ <!-- ROW 3: Integration -->
74
  <div class="row">
75
  <div class="col-full">
76
  <div id="integral-chart" class="chart"></div>
 
84
  const volDiv = document.getElementById('vol-chart');
85
  const diffDiv = document.getElementById('diff-chart');
86
  const intDiv = document.getElementById('integral-chart');
 
87
  const statusDiv = document.getElementById('status');
88
 
89
+ let initPrice=0, initImbP=0, initVol=0, initDiff=0, initInt=0;
 
90
 
91
  const commonConfig = {{ responsive: true, displayModeBar: false }};
92
  const commonLayout = {{
 
104
  const res = await fetch('/data');
105
  const data = await res.json();
106
 
107
+ if (data.error) {{ statusDiv.innerHTML = "Waiting for data..."; return; }}
108
+
109
+ // --- SHARPNESS DISPLAY LOGIC ---
110
+ let slope = data.sharpness;
111
+ let slopeColor = '#aaa';
112
+ let slopeText = 'Neutral';
113
+
114
+ // Thresholds for sharpness (adjust as needed)
115
+ if (slope > 0.5) {{ slopeColor = '#00e676'; slopeText = 'Sharp BUY Wall'; }}
116
+ else if (slope < -0.5) {{ slopeColor = '#ff1744'; slopeText = 'Sharp SELL Wall'; }}
117
+ else if (slope > 0) {{ slopeColor = '#81c784'; slopeText = 'Leaning Buy'; }}
118
+ else {{ slopeColor = '#e57373'; slopeText = 'Leaning Sell'; }}
119
+
120
+ statusDiv.innerHTML = `
121
+ Mid: <span class="${{data.mid >= data.prev_mid ? 'green' : 'red'}}">$${{data.mid.toLocaleString(undefined, {{minimumFractionDigits: 0}})}}</span> |
122
+ Wall Sharpness: <span style="color:${{slopeColor}}; font-weight:bold;">${{slope.toFixed(2)}} (${{slopeText}})</span> |
123
+ Trend: ${{data.integral.last_val.toFixed(0)}}
124
+ `;
125
+
126
+ // 1. PRICE
127
+ if (!initPrice) {{ Plotly.newPlot(priceDiv, [{{ x: data.history.map(d=>new Date(d.t*1000)), y: data.history.map(d=>d.p), type:'scatter', mode:'lines', line:{{color:'#29b6f6'}} }}], {{...commonLayout, title:'Midprice'}}, commonConfig); initPrice=1; }}
128
+ else {{ Plotly.react(priceDiv, [{{ x: data.history.map(d=>new Date(d.t*1000)), y: data.history.map(d=>d.p), type:'scatter', mode:'lines', line:{{color:'#29b6f6'}} }}], {{...commonLayout, title:'Midprice'}}, commonConfig); }}
129
+
130
+ // 2. PRESSURE % (With annotation for sharpness?)
131
+ if (!initImbP) {{ Plotly.newPlot(imbPercentDiv, [{{ x: data.imbalance_pct.x, y: data.imbalance_pct.y, type:'scatter', mode:'lines', fill:'tozeroy', line:{{color:'#ffeb3b'}} }}], {{...commonLayout, title:'Pressure %', yaxis:{{range:[-105,105], gridcolor:'#222'}}}}, commonConfig); initImbP=1; }}
132
+ else {{ Plotly.react(imbPercentDiv, [{{ x: data.imbalance_pct.x, y: data.imbalance_pct.y, type:'scatter', mode:'lines', fill:'tozeroy', line:{{color:'#ffeb3b'}} }}], {{...commonLayout, title:'Pressure %', yaxis:{{range:[-105,105], gridcolor:'#222'}}}}, commonConfig); }}
133
+
134
+ // 3. VOLUME
135
+ if (!initVol) {{ Plotly.newPlot(volDiv, [
136
+ {{ x: data.imbalance_vol.dist_bids, y: data.imbalance_vol.vol_bids, type:'scatter', line:{{color:'#00e676'}} }},
137
+ {{ x: data.imbalance_vol.dist_asks, y: data.imbalance_vol.vol_asks, type:'scatter', line:{{color:'#ff1744'}} }}
138
+ ], {{...commonLayout, title:'Volume'}}, commonConfig); initVol=1; }}
139
+ else {{ Plotly.react(volDiv, [
140
+ {{ x: data.imbalance_vol.dist_bids, y: data.imbalance_vol.vol_bids, type:'scatter', line:{{color:'#00e676'}} }},
141
+ {{ x: data.imbalance_vol.dist_asks, y: data.imbalance_vol.vol_asks, type:'scatter', line:{{color:'#ff1744'}} }}
142
+ ], {{...commonLayout, title:'Volume'}}, commonConfig); }}
143
 
144
  // 4. NET DIFF
145
+ if (!initDiff) {{ Plotly.newPlot(diffDiv, [{{ x: data.diff.x, y: data.diff.y, type:'scatter', mode:'lines', fill:'tozeroy', line:{{color:'#00bcd4'}} }}], {{...commonLayout, title:'Net Diff'}}, commonConfig); initDiff=1; }}
146
+ else {{ Plotly.react(diffDiv, [{{ x: data.diff.x, y: data.diff.y, type:'scatter', mode:'lines', fill:'tozeroy', line:{{color:'#00bcd4'}} }}], {{...commonLayout, title:'Net Diff'}}, commonConfig); }}
147
+
148
+ // 5. INTEGRAL
149
+ let intColor = data.integral.last_val >= 0 ? '#e040fb' : '#e040fb';
150
+ if (!initInt) {{ Plotly.newPlot(intDiv, [{{ x: data.integral.x, y: data.integral.y, type:'scatter', mode:'lines', fill:'tozeroy', line:{{color:intColor}} }}], {{...commonLayout, title:'Integral Trend'}}, commonConfig); initInt=1; }}
151
+ else {{ Plotly.react(intDiv, [{{ x: data.integral.x, y: data.integral.y, type:'scatter', mode:'lines', fill:'tozeroy', line:{{color:intColor}} }}], {{...commonLayout, title:'Integral Trend'}}, commonConfig); }}
 
 
 
 
 
152
 
153
  }} catch (e) {{ console.error("Fetch error:", e); }}
154
  }}
 
212
 
213
  mid = market_state['current_mid']
214
 
215
+ # --- Prepare Data ---
216
  raw_bids = sorted(market_state['bids'].items(), key=lambda x: -x[0])[:300]
217
  raw_asks = sorted(market_state['asks'].items(), key=lambda x: x[0])[:300]
218
 
219
+ # Volumes by distance
220
  dist_bids = [(mid - p, q) for p, q in raw_bids if mid - p >= 0]
221
  d_b_x, d_b_y = [], []
222
  cum_d = 0
 
236
  diff_x, diff_y = [], []
237
  int_x, int_y = [], []
238
  running_int = 0
239
+ sharpness = 0
240
 
241
  if d_b_x and d_a_x:
242
  max_dist = min(d_b_x[-1], d_a_x[-1])
243
  step_size = max_dist / 100
244
  steps = [i * step_size for i in range(1, 101)]
245
 
246
+ for i, s in enumerate(steps):
247
+ # 1. Volume Lookups
248
  idx_b = bisect.bisect_right(d_b_x, s)
249
  vol_b = d_b_y[idx_b-1] if idx_b > 0 else 0
250
 
 
262
  diff_x.append(s)
263
  diff_y.append(diff)
264
 
265
+ # 4. Integral
266
  running_int += diff
267
  int_x.append(s)
268
  int_y.append(running_int)
269
+
270
+ # --- SHARPNESS CALCULATION ---
271
+ # We take the pressure at the 5th step (approx 5% into the book)
272
+ # Sharpness = Pressure / Distance
273
+ target_idx = 4 # 5th element
274
+ if len(imb_x) > target_idx:
275
+ # e.g., Pressure is 50% at $10 distance -> Sharpness = 5.0
276
+ # Dividing by distance normalizes it.
277
+ if imb_x[target_idx] > 0:
278
+ sharpness = imb_y[target_idx] / imb_x[target_idx]
279
 
280
  return web.json_response({
281
  "mid": mid,
282
  "prev_mid": market_state['history'][-2]['p'] if len(market_state['history']) > 1 else mid,
283
+ "sharpness": sharpness,
284
  "imbalance_vol": { "dist_bids": d_b_x, "vol_bids": d_b_y, "dist_asks": d_a_x, "vol_asks": d_a_y },
285
  "imbalance_pct": { "x": imb_x, "y": imb_y },
286
  "diff": { "x": diff_x, "y": diff_y },
 
308
  site = web.TCPSite(runner, '0.0.0.0', PORT)
309
  await site.start()
310
 
311
+ print(f"πŸš€ BTC-USD Dashboard with Sharpness: http://localhost:{PORT}")
312
  await asyncio.Event().wait()
313
 
314
  if __name__ == "__main__":