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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +52 -51
app.py CHANGED
@@ -28,23 +28,21 @@ HTML_PAGE = f"""
28
  <!DOCTYPE html>
29
  <html>
30
  <head>
31
- <title>BTC-USD Net Liquidity</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 */
37
  #container {{ display: flex; flex-direction: column; height: 100vh; width: 100vw; }}
38
 
39
- /* Row 1: Price & Pressure % */
40
- #row-top {{ flex: 1; display: flex; width: 100%; border-bottom: 1px solid #333; }}
41
 
42
- /* Row 2: Volume & Net Difference */
43
- #row-bot {{ flex: 1; display: flex; width: 100%; }}
44
-
45
  /* Columns */
46
  .col-left {{ width: 50%; border-right: 1px solid #333; position: relative; }}
47
  .col-right {{ width: 50%; position: relative; }}
 
48
 
49
  /* Charts fill their containers */
50
  .chart {{ width: 100%; height: 100%; }}
@@ -59,8 +57,8 @@ HTML_PAGE = f"""
59
  <div id="status">Connecting...</div>
60
 
61
  <div id="container">
62
- <!-- TOP ROW -->
63
- <div id="row-top">
64
  <div class="col-left">
65
  <div id="price-chart" class="chart"></div>
66
  </div>
@@ -69,16 +67,22 @@ HTML_PAGE = f"""
69
  </div>
70
  </div>
71
 
72
- <!-- BOTTOM ROW -->
73
- <div id="row-bot">
74
  <div class="col-left">
75
  <div id="vol-chart" class="chart"></div>
76
  </div>
77
  <div class="col-right">
78
- <!-- Replaced Integral with Net Difference -->
79
  <div id="diff-chart" class="chart"></div>
80
  </div>
81
  </div>
 
 
 
 
 
 
 
82
  </div>
83
 
84
  <script>
@@ -86,20 +90,19 @@ HTML_PAGE = f"""
86
  const imbPercentDiv = document.getElementById('imb-percent-chart');
87
  const volDiv = document.getElementById('vol-chart');
88
  const diffDiv = document.getElementById('diff-chart');
 
89
 
90
  const statusDiv = document.getElementById('status');
91
 
92
- let initPrice = false;
93
- let initImbP = false;
94
- let initVol = false;
95
- let initDiff = false;
96
 
97
  const commonConfig = {{ responsive: true, displayModeBar: false }};
98
  const commonLayout = {{
99
  paper_bgcolor: '#0e0e0e',
100
  plot_bgcolor: '#0e0e0e',
101
  font: {{ color: '#aaa' }},
102
- margin: {{ t: 40, b: 30, l: 50, r: 20 }},
103
  showlegend: false,
104
  xaxis: {{ gridcolor: '#222' }},
105
  yaxis: {{ gridcolor: '#222' }}
@@ -115,27 +118,25 @@ HTML_PAGE = f"""
115
  return;
116
  }}
117
 
118
- statusDiv.innerHTML = `Mid: <span class="${{data.mid >= data.prev_mid ? 'green' : 'red'}}">$${{data.mid.toLocaleString(undefined, {{minimumFractionDigits: 2}})}}</span> | Net Diff: ${{data.diff.last_val ? data.diff.last_val.toFixed(4) : 0}}`;
119
 
120
  // 1. PRICE HISTORY
121
  if (!initPrice) {{
122
  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}} }}],
123
- {{ ...commonLayout, title: '<b>Midprice History</b>', xaxis: {{type:'date', gridcolor:'#222'}} }}, commonConfig);
124
  initPrice = true;
125
  }} else {{
126
  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}} }}],
127
- {{ ...commonLayout, title: '<b>Midprice History</b>', xaxis: {{type:'date', gridcolor:'#222'}} }}, commonConfig);
128
  }}
129
 
130
  // 2. IMBALANCE %
131
- const layoutImbP = {{ ...commonLayout, title: '<b>Liquidity Pressure (%)</b>', xaxis: {{title: 'Distance ($)', gridcolor:'#222'}}, yaxis: {{range: [-105, 105], gridcolor:'#222', zeroline: true}} }};
132
- const traceImbP = {{ x: data.imbalance_pct.x, y: data.imbalance_pct.y, type: 'scatter', mode: 'lines', fill: 'tozeroy', line: {{color: '#ffeb3b', width: 2}} }};
133
-
134
- if (!initImbP) {{ Plotly.newPlot(imbPercentDiv, [traceImbP], layoutImbP, commonConfig); initImbP = true; }}
135
- else {{ Plotly.react(imbPercentDiv, [traceImbP], layoutImbP, commonConfig); }}
136
 
137
  // 3. VOLUME BY DISTANCE
138
- const layoutVol = {{ ...commonLayout, title: '<b>Volume by Distance</b>', xaxis: {{title: 'Distance ($)', gridcolor:'#222'}} }};
139
  const tracesVol = [
140
  {{ x: data.imbalance_vol.dist_bids, y: data.imbalance_vol.vol_bids, type: 'scatter', name: 'Bid', line: {{color: '#00e676'}} }},
141
  {{ x: data.imbalance_vol.dist_asks, y: data.imbalance_vol.vol_asks, type: 'scatter', name: 'Ask', line: {{color: '#ff1744'}} }}
@@ -143,25 +144,20 @@ HTML_PAGE = f"""
143
  if (!initVol) {{ Plotly.newPlot(volDiv, tracesVol, layoutVol, commonConfig); initVol = true; }}
144
  else {{ Plotly.react(volDiv, tracesVol, layoutVol, commonConfig); }}
145
 
146
- // 4. NET DIFFERENCE (New Graph)
147
- const layoutDiff = {{ ...commonLayout,
148
- title: '<b>Net Liquidity (Bids - Asks)</b>',
149
- xaxis: {{title: 'Distance ($)', gridcolor:'#222'}},
150
- yaxis: {{title: 'Volume Diff', gridcolor:'#222', zeroline: true}}
151
- }};
152
-
153
- const traceDiff = {{
154
- x: data.diff.x,
155
- y: data.diff.y,
156
- type: 'scatter',
157
- mode: 'lines',
158
- fill: 'tozeroy',
159
- line: {{color: '#00bcd4', width: 2}} // Cyan line
160
- }};
161
-
162
  if (!initDiff) {{ Plotly.newPlot(diffDiv, [traceDiff], layoutDiff, commonConfig); initDiff = true; }}
163
  else {{ Plotly.react(diffDiv, [traceDiff], layoutDiff, commonConfig); }}
164
 
 
 
 
 
 
 
 
 
165
  }} catch (e) {{ console.error("Fetch error:", e); }}
166
  }}
167
 
@@ -243,9 +239,11 @@ async def handle_data(request):
243
  cum_d += q
244
  d_a_x.append(d); d_a_y.append(cum_d)
245
 
246
- # --- Imbalance & Net Difference ---
247
  imb_x, imb_y = [], []
248
  diff_x, diff_y = [], []
 
 
249
 
250
  if d_b_x and d_a_x:
251
  max_dist = min(d_b_x[-1], d_a_x[-1])
@@ -260,26 +258,29 @@ async def handle_data(request):
260
  idx_a = bisect.bisect_right(d_a_x, s)
261
  vol_a = d_a_y[idx_a-1] if idx_a > 0 else 0
262
 
263
- total_vol = vol_b + vol_a
264
-
265
  # 2. Imbalance %
266
- pct = 0
267
- if total_vol > 0:
268
- pct = ((vol_b - vol_a) / total_vol) * 100
269
  imb_x.append(s)
270
  imb_y.append(pct)
271
 
272
- # 3. Net Difference (Raw Volume)
273
  diff = vol_b - vol_a
274
  diff_x.append(s)
275
  diff_y.append(diff)
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, "last_val": diff_y[-1] if diff_y else 0 },
 
283
  "history": market_state['history']
284
  })
285
 
@@ -303,7 +304,7 @@ async def main():
303
  site = web.TCPSite(runner, '0.0.0.0', PORT)
304
  await site.start()
305
 
306
- print(f"🚀 BTC-USD Net Liquidity Dashboard: http://localhost:{PORT}")
307
  await asyncio.Event().wait()
308
 
309
  if __name__ == "__main__":
 
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%; }}
 
57
  <div id="status">Connecting...</div>
58
 
59
  <div id="container">
60
+ <!-- ROW 1: Price & Pressure % -->
61
+ <div class="row">
62
  <div class="col-left">
63
  <div id="price-chart" class="chart"></div>
64
  </div>
 
67
  </div>
68
  </div>
69
 
70
+ <!-- ROW 2: Volume & Net Diff -->
71
+ <div class="row">
72
  <div class="col-left">
73
  <div id="vol-chart" class="chart"></div>
74
  </div>
75
  <div class="col-right">
 
76
  <div id="diff-chart" class="chart"></div>
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>
84
+ </div>
85
+ </div>
86
  </div>
87
 
88
  <script>
 
90
  const imbPercentDiv = document.getElementById('imb-percent-chart');
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 = {{
102
  paper_bgcolor: '#0e0e0e',
103
  plot_bgcolor: '#0e0e0e',
104
  font: {{ color: '#aaa' }},
105
+ margin: {{ t: 30, b: 25, l: 40, r: 20 }},
106
  showlegend: false,
107
  xaxis: {{ gridcolor: '#222' }},
108
  yaxis: {{ gridcolor: '#222' }}
 
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'}} }}
 
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
  }}
163
 
 
239
  cum_d += q
240
  d_a_x.append(d); d_a_y.append(cum_d)
241
 
242
+ # --- Calculations ---
243
  imb_x, imb_y = [], []
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])
 
258
  idx_a = bisect.bisect_right(d_a_x, s)
259
  vol_a = d_a_y[idx_a-1] if idx_a > 0 else 0
260
 
 
 
261
  # 2. Imbalance %
262
+ total_vol = vol_b + vol_a
263
+ pct = ((vol_b - vol_a) / total_vol) * 100 if total_vol > 0 else 0
 
264
  imb_x.append(s)
265
  imb_y.append(pct)
266
 
267
+ # 3. Net Diff
268
  diff = vol_b - vol_a
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 },
283
+ "integral": { "x": int_x, "y": int_y, "last_val": int_y[-1] if int_y else 0 },
284
  "history": market_state['history']
285
  })
286
 
 
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__":