Alvin3y1 commited on
Commit
bfed924
·
verified ·
1 Parent(s): 017f664

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +51 -99
app.py CHANGED
@@ -11,11 +11,7 @@ SYMBOL_KRAKEN = "BTC/USD"
11
  PORT = 7860
12
  HISTORY_LENGTH = 300
13
  BROADCAST_RATE = 0.1
14
-
15
- DECAY_LAMBDA_SHORT = 100.0
16
- DECAY_LAMBDA_LONG = 500.0
17
- DECAY_LAMBDA_MACRO = 15000.0
18
-
19
  IMPACT_SENSITIVITY = 0.5
20
 
21
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
@@ -24,9 +20,7 @@ market_state = {
24
  "bids": {},
25
  "asks": {},
26
  "history": [],
27
- "pred_history_short": [],
28
- "pred_history_long": [],
29
- "pred_history_macro": [],
30
  "current_mid": 0.0,
31
  "prev_mid": 0.0,
32
  "ready": False
@@ -38,9 +32,7 @@ def analyze_structure(diff_x, diff_y, current_mid):
38
  if not diff_y or len(diff_y) < 5:
39
  return None
40
 
41
- w_short = 0.0
42
- w_long = 0.0
43
- w_macro = 0.0
44
  prev_vol = 0.0
45
 
46
  for i in range(len(diff_x)):
@@ -50,20 +42,21 @@ def analyze_structure(diff_x, diff_y, current_mid):
50
  marginal_vol = cum_vol - prev_vol
51
  prev_vol = cum_vol
52
 
53
- w_short += marginal_vol * math.exp(-dist / DECAY_LAMBDA_SHORT)
54
- w_long += marginal_vol * math.exp(-dist / DECAY_LAMBDA_LONG)
55
- w_macro += marginal_vol * math.exp(-dist / DECAY_LAMBDA_MACRO)
 
 
 
 
 
 
56
 
57
- def get_impact(w_imb):
58
- if w_imb == 0: return 0.0
59
- imp = math.sqrt(abs(w_imb)) * IMPACT_SENSITIVITY
60
- return -imp if w_imb < 0 else imp
61
 
62
  return {
63
- "proj_short": current_mid + get_impact(w_short),
64
- "proj_long": current_mid + get_impact(w_long),
65
- "proj_macro": current_mid + get_impact(w_macro),
66
- "net_score": w_short
67
  }
68
 
69
  def process_market_data():
@@ -72,8 +65,8 @@ def process_market_data():
72
 
73
  mid = market_state['current_mid']
74
 
75
- raw_bids = sorted(market_state['bids'].items(), key=lambda x: -x[0])[:1000]
76
- raw_asks = sorted(market_state['asks'].items(), key=lambda x: x[0])[:1000]
77
 
78
  d_b_x, d_b_y, cum = [], [], 0
79
  for p, q in raw_bids:
@@ -113,25 +106,15 @@ def process_market_data():
113
 
114
  now = time.time()
115
  if analysis:
116
- if not market_state['pred_history_short'] or (now - market_state['pred_history_short'][-1]['t'] > 0.5):
117
- market_state['pred_history_short'].append({'t': now, 'p': analysis['proj_short']})
118
- if len(market_state['pred_history_short']) > HISTORY_LENGTH:
119
- market_state['pred_history_short'].pop(0)
120
-
121
- market_state['pred_history_long'].append({'t': now, 'p': analysis['proj_long']})
122
- if len(market_state['pred_history_long']) > HISTORY_LENGTH:
123
- market_state['pred_history_long'].pop(0)
124
-
125
- market_state['pred_history_macro'].append({'t': now, 'p': analysis['proj_macro']})
126
- if len(market_state['pred_history_macro']) > HISTORY_LENGTH:
127
- market_state['pred_history_macro'].pop(0)
128
 
129
  return {
130
  "mid": mid,
131
  "history": market_state['history'],
132
- "pred_history_short": market_state['pred_history_short'],
133
- "pred_history_long": market_state['pred_history_long'],
134
- "pred_history_macro": market_state['pred_history_macro'],
135
  "depth_x": diff_x,
136
  "depth_net": diff_y,
137
  "depth_bids": chart_bids,
@@ -153,8 +136,6 @@ HTML_PAGE = f"""
153
  --text-main: #c5c6c7;
154
  --accent-green: #66fcf1;
155
  --accent-red: #ff3b3b;
156
- --accent-purple: #ce93d8;
157
- --accent-cyan: #4dd0e1;
158
  --border: #2d3842;
159
  }}
160
  body {{ margin: 0; padding: 0; background-color: var(--bg-color); color: var(--text-main); font-family: monospace; overflow: hidden; height: 100vh; width: 100vw; }}
@@ -187,8 +168,6 @@ HTML_PAGE = f"""
187
  .stat-value {{ font-size: 24px; font-weight: bold; }}
188
  .green {{ color: var(--accent-green); }}
189
  .red {{ color: var(--accent-red); }}
190
- .purple {{ color: var(--accent-purple); }}
191
- .cyan {{ color: var(--accent-cyan); }}
192
 
193
  #loader {{ position: absolute; top:0; left:0; width:100%; height:100%; background: rgba(0,0,0,0.95); z-index: 999; display: flex; flex-direction: column; justify-content: center; align-items: center; color: var(--accent-green); }}
194
  </style>
@@ -221,20 +200,12 @@ HTML_PAGE = f"""
221
  <div class="panel-header">HFT ANALYTICS ENGINE</div>
222
  <div class="stats-content">
223
  <div class="stat-box">
224
- <span class="stat-label">WEIGHTED IMBALANCE (SCALP)</span>
225
  <span id="score-val" class="stat-value">0</span>
226
  </div>
227
  <div class="stat-box" style="border: 1px solid #444;">
228
- <span class="stat-label" style="color:#aaa;">SHORT TERM TARGET</span>
229
- <span id="proj-short" class="stat-value">---</span>
230
- </div>
231
- <div class="stat-box" style="border: 1px solid #7b1fa2;">
232
- <span class="stat-label" style="color:var(--accent-purple);">LONG TERM (SWING)</span>
233
- <span id="proj-long" class="stat-value purple">---</span>
234
- </div>
235
- <div class="stat-box" style="border: 1px solid #00acc1;">
236
- <span class="stat-label" style="color:var(--accent-cyan);">MACRO (WHALE)</span>
237
- <span id="proj-macro" class="stat-value cyan">---</span>
238
  </div>
239
  </div>
240
  </div>
@@ -247,9 +218,7 @@ HTML_PAGE = f"""
247
  status: document.getElementById('loading-status'),
248
  price: document.getElementById('live-price'),
249
  scoreVal: document.getElementById('score-val'),
250
- projShort: document.getElementById('proj-short'),
251
- projLong: document.getElementById('proj-long'),
252
- projMacro: document.getElementById('proj-macro')
253
  }};
254
 
255
  const chartCommon = {{
@@ -261,24 +230,28 @@ HTML_PAGE = f"""
261
  }};
262
 
263
  const priceChart = LightweightCharts.createChart(document.getElementById('tv-price'), chartCommon);
264
-
265
  const priceSeries = priceChart.addLineSeries({{ color: '#2962FF', lineWidth: 2, title: 'Price' }});
266
 
267
- const pastShortSeries = priceChart.addLineSeries({{ color: '#555555', lineWidth: 1, title: 'Short (Past)' }});
268
- const futureShortSeries = priceChart.addLineSeries({{ color: '#ff9800', lineWidth: 2, lineStyle: 2, title: 'Short (Fut)' }});
 
 
 
269
 
270
- const pastLongSeries = priceChart.addLineSeries({{ color: '#7b1fa2', lineWidth: 1, title: 'Long (Past)' }});
271
-
272
- const pastMacroSeries = priceChart.addLineSeries({{ color: '#4dd0e1', lineWidth: 1, title: 'Macro (Past)' }});
273
- const futureMacroSeries = priceChart.addLineSeries({{ color: '#00bcd4', lineWidth: 2, lineStyle: 2, title: 'Macro (Fut)' }});
 
 
274
 
275
  const rawChart = LightweightCharts.createChart(document.getElementById('tv-raw'), {{
276
  ...chartCommon,
277
  timeScale: {{ tickMarkFormatter: (time) => parseFloat(time).toFixed(0) }},
278
  localization: {{ timeFormatter: (time) => 'Dist: $' + parseFloat(time).toFixed(2) }}
279
  }});
280
- const rawBidSeries = rawChart.addAreaSeries({{ lineColor: '#00e676', topColor: 'rgba(0, 230, 118, 0.2)', bottomColor: 'rgba(0, 230, 118, 0.0)', lineWidth: 2 }});
281
- const rawAskSeries = rawChart.addAreaSeries({{ lineColor: '#ff1744', topColor: 'rgba(255, 23, 68, 0.2)', bottomColor: 'rgba(255, 23, 68, 0.0)', lineWidth: 2 }});
282
 
283
  const netChart = LightweightCharts.createChart(document.getElementById('tv-net'), {{
284
  ...chartCommon,
@@ -322,52 +295,31 @@ HTML_PAGE = f"""
322
  if (!seen.has(t)) {{ seen.add(t); cleanHistory.push({{ time: t, value: d.p }}); }}
323
  }});
324
 
325
- const predShort = [];
326
- const seenS = new Set();
327
- if(data.pred_history_short) {{
328
- data.pred_history_short.forEach(d => {{
329
  const t = Math.floor(d.t);
330
- if(!seenS.has(t)) {{ seenS.add(t); predShort.push({{ time: t, value: d.p }}); }}
331
- }});
332
- }}
333
-
334
- const predLong = [];
335
- const seenL = new Set();
336
- if(data.pred_history_long) {{
337
- data.pred_history_long.forEach(d => {{
338
- const t = Math.floor(d.t);
339
- if(!seenL.has(t)) {{ seenL.add(t); predLong.push({{ time: t, value: d.p }}); }}
340
- }});
341
- }}
342
-
343
- const predMacro = [];
344
- const seenM = new Set();
345
- if(data.pred_history_macro) {{
346
- data.pred_history_macro.forEach(d => {{
347
- const t = Math.floor(d.t);
348
- if(!seenM.has(t)) {{ seenM.add(t); predMacro.push({{ time: t, value: d.p }}); }}
349
  }});
350
  }}
351
 
352
  if (cleanHistory.length) {{
353
  priceSeries.setData(cleanHistory);
354
- pastShortSeries.setData(predShort);
355
- pastLongSeries.setData(predLong);
356
- pastMacroSeries.setData(predMacro);
357
 
358
  const last = cleanHistory[cleanHistory.length-1];
359
  dom.price.innerText = last.value.toLocaleString(undefined, {{minimumFractionDigits: 2}});
360
 
361
  if (data.analysis) {{
362
- const {{ proj_short, proj_long, proj_macro, net_score }} = data.analysis;
363
-
364
- futureShortSeries.setData([last, {{ time: last.time + 60, value: proj_short }}]);
365
 
366
- futureMacroSeries.setData([last, {{ time: last.time + 3600, value: proj_macro }}]);
 
 
 
367
 
368
- dom.projShort.innerText = proj_short.toLocaleString(undefined, {{minimumFractionDigits: 0, maximumFractionDigits: 0}});
369
- dom.projLong.innerText = proj_long.toLocaleString(undefined, {{minimumFractionDigits: 0, maximumFractionDigits: 0}});
370
- dom.projMacro.innerText = proj_macro.toLocaleString(undefined, {{minimumFractionDigits: 0, maximumFractionDigits: 0}});
371
 
372
  dom.scoreVal.innerText = net_score.toFixed(2);
373
  dom.scoreVal.className = net_score > 0 ? "stat-value green" : "stat-value red";
 
11
  PORT = 7860
12
  HISTORY_LENGTH = 300
13
  BROADCAST_RATE = 0.1
14
+ DECAY_LAMBDA = 100.0
 
 
 
 
15
  IMPACT_SENSITIVITY = 0.5
16
 
17
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
 
20
  "bids": {},
21
  "asks": {},
22
  "history": [],
23
+ "pred_history": [],
 
 
24
  "current_mid": 0.0,
25
  "prev_mid": 0.0,
26
  "ready": False
 
32
  if not diff_y or len(diff_y) < 5:
33
  return None
34
 
35
+ weighted_imbalance = 0.0
 
 
36
  prev_vol = 0.0
37
 
38
  for i in range(len(diff_x)):
 
42
  marginal_vol = cum_vol - prev_vol
43
  prev_vol = cum_vol
44
 
45
+ weight = math.exp(-dist / DECAY_LAMBDA)
46
+ weighted_imbalance += marginal_vol * weight
47
+
48
+ if weighted_imbalance != 0:
49
+ impact = math.sqrt(abs(weighted_imbalance)) * IMPACT_SENSITIVITY
50
+ if weighted_imbalance < 0:
51
+ impact = -impact
52
+ else:
53
+ impact = 0.0
54
 
55
+ projected_price = current_mid + impact
 
 
 
56
 
57
  return {
58
+ "projected": projected_price,
59
+ "net_score": weighted_imbalance
 
 
60
  }
61
 
62
  def process_market_data():
 
65
 
66
  mid = market_state['current_mid']
67
 
68
+ raw_bids = sorted(market_state['bids'].items(), key=lambda x: -x[0])[:300]
69
+ raw_asks = sorted(market_state['asks'].items(), key=lambda x: x[0])[:300]
70
 
71
  d_b_x, d_b_y, cum = [], [], 0
72
  for p, q in raw_bids:
 
106
 
107
  now = time.time()
108
  if analysis:
109
+ if not market_state['pred_history'] or (now - market_state['pred_history'][-1]['t'] > 0.5):
110
+ market_state['pred_history'].append({'t': now, 'p': analysis['projected']})
111
+ if len(market_state['pred_history']) > HISTORY_LENGTH:
112
+ market_state['pred_history'].pop(0)
 
 
 
 
 
 
 
 
113
 
114
  return {
115
  "mid": mid,
116
  "history": market_state['history'],
117
+ "pred_history": market_state['pred_history'],
 
 
118
  "depth_x": diff_x,
119
  "depth_net": diff_y,
120
  "depth_bids": chart_bids,
 
136
  --text-main: #c5c6c7;
137
  --accent-green: #66fcf1;
138
  --accent-red: #ff3b3b;
 
 
139
  --border: #2d3842;
140
  }}
141
  body {{ margin: 0; padding: 0; background-color: var(--bg-color); color: var(--text-main); font-family: monospace; overflow: hidden; height: 100vh; width: 100vw; }}
 
168
  .stat-value {{ font-size: 24px; font-weight: bold; }}
169
  .green {{ color: var(--accent-green); }}
170
  .red {{ color: var(--accent-red); }}
 
 
171
 
172
  #loader {{ position: absolute; top:0; left:0; width:100%; height:100%; background: rgba(0,0,0,0.95); z-index: 999; display: flex; flex-direction: column; justify-content: center; align-items: center; color: var(--accent-green); }}
173
  </style>
 
200
  <div class="panel-header">HFT ANALYTICS ENGINE</div>
201
  <div class="stats-content">
202
  <div class="stat-box">
203
+ <span class="stat-label">WEIGHTED IMBALANCE SCORE</span>
204
  <span id="score-val" class="stat-value">0</span>
205
  </div>
206
  <div class="stat-box" style="border: 1px solid #444;">
207
+ <span class="stat-label" style="color:var(--accent-green);">IMPACT PROJECTION</span>
208
+ <span id="proj-val" class="stat-value">---</span>
 
 
 
 
 
 
 
 
209
  </div>
210
  </div>
211
  </div>
 
218
  status: document.getElementById('loading-status'),
219
  price: document.getElementById('live-price'),
220
  scoreVal: document.getElementById('score-val'),
221
+ projVal: document.getElementById('proj-val')
 
 
222
  }};
223
 
224
  const chartCommon = {{
 
230
  }};
231
 
232
  const priceChart = LightweightCharts.createChart(document.getElementById('tv-price'), chartCommon);
 
233
  const priceSeries = priceChart.addLineSeries({{ color: '#2962FF', lineWidth: 2, title: 'Price' }});
234
 
235
+ const pastPredSeries = priceChart.addLineSeries({{
236
+ color: '#555555',
237
+ lineWidth: 1,
238
+ title: 'Past Prediction'
239
+ }});
240
 
241
+ const futurePredSeries = priceChart.addLineSeries({{
242
+ color: '#ff9800',
243
+ lineWidth: 2,
244
+ lineStyle: 2,
245
+ title: 'Projection'
246
+ }});
247
 
248
  const rawChart = LightweightCharts.createChart(document.getElementById('tv-raw'), {{
249
  ...chartCommon,
250
  timeScale: {{ tickMarkFormatter: (time) => parseFloat(time).toFixed(0) }},
251
  localization: {{ timeFormatter: (time) => 'Dist: $' + parseFloat(time).toFixed(2) }}
252
  }});
253
+ const rawBidSeries = rawChart.addAreaSeries({{ lineColor: '#00e676', topColor: 'rgba(0, 230, 118, 0.2)', bottomColor: 'rgba(0, 230, 118, 0.0)', lineWidth: 2, title: "Bids" }});
254
+ const rawAskSeries = rawChart.addAreaSeries({{ lineColor: '#ff1744', topColor: 'rgba(255, 23, 68, 0.2)', bottomColor: 'rgba(255, 23, 68, 0.0)', lineWidth: 2, title: "Asks" }});
255
 
256
  const netChart = LightweightCharts.createChart(document.getElementById('tv-net'), {{
257
  ...chartCommon,
 
295
  if (!seen.has(t)) {{ seen.add(t); cleanHistory.push({{ time: t, value: d.p }}); }}
296
  }});
297
 
298
+ const predHistory = [];
299
+ const seenP = new Set();
300
+ if(data.pred_history) {{
301
+ data.pred_history.forEach(d => {{
302
  const t = Math.floor(d.t);
303
+ if(!seenP.has(t)) {{ seenP.add(t); predHistory.push({{ time: t, value: d.p }}); }}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
304
  }});
305
  }}
306
 
307
  if (cleanHistory.length) {{
308
  priceSeries.setData(cleanHistory);
309
+ pastPredSeries.setData(predHistory);
 
 
310
 
311
  const last = cleanHistory[cleanHistory.length-1];
312
  dom.price.innerText = last.value.toLocaleString(undefined, {{minimumFractionDigits: 2}});
313
 
314
  if (data.analysis) {{
315
+ const {{ projected, net_score }} = data.analysis;
 
 
316
 
317
+ futurePredSeries.setData([
318
+ last,
319
+ {{ time: last.time + 60, value: projected }}
320
+ ]);
321
 
322
+ dom.projVal.innerText = projected.toLocaleString(undefined, {{minimumFractionDigits: 0, maximumFractionDigits: 0}});
 
 
323
 
324
  dom.scoreVal.innerText = net_score.toFixed(2);
325
  dom.scoreVal.className = net_score > 0 ? "stat-value green" : "stat-value red";