Update app.py
Browse files
app.py
CHANGED
|
@@ -100,7 +100,6 @@ def calculate_polr(bids, asks, mid):
|
|
| 100 |
"""
|
| 101 |
Path of Least Resistance:
|
| 102 |
Simulates eating volume on both sides.
|
| 103 |
-
Returns the price path where liquidity is thinnest.
|
| 104 |
"""
|
| 105 |
if not bids or not asks: return []
|
| 106 |
|
|
@@ -109,9 +108,9 @@ def calculate_polr(bids, asks, mid):
|
|
| 109 |
|
| 110 |
path_points = []
|
| 111 |
|
| 112 |
-
#
|
| 113 |
-
#
|
| 114 |
-
volume_steps = [i *
|
| 115 |
|
| 116 |
current_time = time.time()
|
| 117 |
|
|
@@ -139,29 +138,21 @@ def calculate_polr(bids, asks, mid):
|
|
| 139 |
bid_cost_dist = mid - target_bid_price
|
| 140 |
|
| 141 |
# 3. Compare Resistance
|
| 142 |
-
# If moving up 10$ costs 5 BTC, but moving down 10$ costs 20 BTC,
|
| 143 |
-
# The path of least resistance is UP (it's thinner).
|
| 144 |
-
|
| 145 |
-
# Here we compare the DISTANCE moved for the SAME volume.
|
| 146 |
-
# If for 5 BTC, Price moves UP $10 and DOWN $2.
|
| 147 |
-
# The UP side is "thinner" (less resistance to price change), so price "slips" up.
|
| 148 |
-
|
| 149 |
-
projected_p = mid
|
| 150 |
-
|
| 151 |
-
# Avoid division by zero or tiny spreads
|
| 152 |
if bid_cost_dist <= 0: bid_cost_dist = 0.01
|
| 153 |
if ask_cost_dist <= 0: ask_cost_dist = 0.01
|
| 154 |
|
| 155 |
-
|
| 156 |
if ask_cost_dist > bid_cost_dist:
|
| 157 |
-
#
|
| 158 |
-
|
|
|
|
|
|
|
|
|
|
| 159 |
else:
|
| 160 |
projected_p = target_bid_price
|
| 161 |
|
| 162 |
-
# Add slight smoothing/dampening so it connects to current price
|
| 163 |
path_points.append({
|
| 164 |
-
'
|
| 165 |
'p': projected_p
|
| 166 |
})
|
| 167 |
|
|
@@ -400,7 +391,7 @@ HTML_PAGE = f"""
|
|
| 400 |
|
| 401 |
<div id="p-chart" class="panel">
|
| 402 |
<div class="chart-header">
|
| 403 |
-
PRICE (BLUE) // <span class="c-purp">
|
| 404 |
</div>
|
| 405 |
<div id="tv-price" style="flex: 1; width: 100%;"></div>
|
| 406 |
</div>
|
|
@@ -478,14 +469,33 @@ HTML_PAGE = f"""
|
|
| 478 |
}};
|
| 479 |
|
| 480 |
const priceChart = LightweightCharts.createChart(document.getElementById('tv-price'), chartOpts);
|
| 481 |
-
const priceSeries = priceChart.addLineSeries({{ color: '#2979ff', lineWidth: 2, title: 'Price' }});
|
| 482 |
|
| 483 |
-
//
|
| 484 |
-
|
|
|
|
|
|
|
| 485 |
|
| 486 |
-
|
| 487 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 488 |
|
|
|
|
|
|
|
|
|
|
| 489 |
const candleChart = LightweightCharts.createChart(document.getElementById('tv-candles'), {{
|
| 490 |
...chartOpts,
|
| 491 |
timeScale: {{ timeVisible: true, secondsVisible: false }}
|
|
@@ -533,19 +543,6 @@ HTML_PAGE = f"""
|
|
| 533 |
}}
|
| 534 |
}}).observe(document.body);
|
| 535 |
|
| 536 |
-
['tv-price', 'tv-candles', 'tv-net', 'sidebar-vol', 'sidebar-density'].forEach(id => {{
|
| 537 |
-
new ResizeObserver(e => {{
|
| 538 |
-
const t = document.getElementById(id);
|
| 539 |
-
if (t.clientWidth && t.clientHeight) {{
|
| 540 |
-
if(id === 'tv-price') priceChart.applyOptions({{ width: t.clientWidth, height: t.clientHeight }});
|
| 541 |
-
if(id === 'tv-candles') candleChart.applyOptions({{ width: t.clientWidth, height: t.clientHeight }});
|
| 542 |
-
if(id === 'tv-net') netChart.applyOptions({{ width: t.clientWidth, height: t.clientHeight }});
|
| 543 |
-
if(id === 'sidebar-vol') volChart.applyOptions({{ width: t.clientWidth, height: t.clientHeight }});
|
| 544 |
-
if(id === 'sidebar-density') denChart.applyOptions({{ width: t.clientWidth, height: t.clientHeight }});
|
| 545 |
-
}}
|
| 546 |
-
}}).observe(document.getElementById(id));
|
| 547 |
-
}});
|
| 548 |
-
|
| 549 |
function connect() {{
|
| 550 |
const ws = new WebSocket((location.protocol === 'https:' ? 'wss' : 'ws') + '://' + location.host + '/ws');
|
| 551 |
|
|
@@ -580,16 +577,19 @@ HTML_PAGE = f"""
|
|
| 580 |
dom.score.style.color = rho > 0 ? "var(--green)" : (rho < 0 ? "var(--red)" : "var(--text-main)");
|
| 581 |
}}
|
| 582 |
|
| 583 |
-
// 2. Purple
|
|
|
|
| 584 |
if (data.polr && data.polr.length) {{
|
| 585 |
-
//
|
| 586 |
-
|
| 587 |
-
|
| 588 |
-
|
| 589 |
-
|
| 590 |
-
|
| 591 |
-
|
| 592 |
-
|
|
|
|
|
|
|
| 593 |
}}
|
| 594 |
}}
|
| 595 |
|
|
|
|
| 100 |
"""
|
| 101 |
Path of Least Resistance:
|
| 102 |
Simulates eating volume on both sides.
|
|
|
|
| 103 |
"""
|
| 104 |
if not bids or not asks: return []
|
| 105 |
|
|
|
|
| 108 |
|
| 109 |
path_points = []
|
| 110 |
|
| 111 |
+
# MODIFIED: Reduced count to 15 distinct lines for performance/clarity
|
| 112 |
+
# Spaced out volume steps to capture depth
|
| 113 |
+
volume_steps = [i * 1.5 for i in range(1, 16)]
|
| 114 |
|
| 115 |
current_time = time.time()
|
| 116 |
|
|
|
|
| 138 |
bid_cost_dist = mid - target_bid_price
|
| 139 |
|
| 140 |
# 3. Compare Resistance
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 141 |
if bid_cost_dist <= 0: bid_cost_dist = 0.01
|
| 142 |
if ask_cost_dist <= 0: ask_cost_dist = 0.01
|
| 143 |
|
| 144 |
+
projected_p = mid
|
| 145 |
if ask_cost_dist > bid_cost_dist:
|
| 146 |
+
# UP is harder, Down is easier -> Price goes UP (slip is normally against liquidity, but POLR suggests price follows ease)
|
| 147 |
+
# Actually, conventionally POLR means price goes where resistance is lowest.
|
| 148 |
+
# If Ask side is THICK (High dist), and Bid side is THIN (Low dist), price falls.
|
| 149 |
+
# Logic revised for visualization: We project where price SLIPS to.
|
| 150 |
+
projected_p = target_ask_price
|
| 151 |
else:
|
| 152 |
projected_p = target_bid_price
|
| 153 |
|
|
|
|
| 154 |
path_points.append({
|
| 155 |
+
'index': i, # Mark the horizon index
|
| 156 |
'p': projected_p
|
| 157 |
})
|
| 158 |
|
|
|
|
| 391 |
|
| 392 |
<div id="p-chart" class="panel">
|
| 393 |
<div class="chart-header">
|
| 394 |
+
PRICE (BLUE) // <span class="c-purp">POLR RIVER (PURPLE FADE)</span> // <span style="color:var(--yellow)">PRED (YELLOW)</span>
|
| 395 |
</div>
|
| 396 |
<div id="tv-price" style="flex: 1; width: 100%;"></div>
|
| 397 |
</div>
|
|
|
|
| 469 |
}};
|
| 470 |
|
| 471 |
const priceChart = LightweightCharts.createChart(document.getElementById('tv-price'), chartOpts);
|
|
|
|
| 472 |
|
| 473 |
+
// --- POLR RIVER INITIALIZATION ---
|
| 474 |
+
// We create an array of series. Index 0 = Nearest Term, Index N = Long Term
|
| 475 |
+
const polrLines = [];
|
| 476 |
+
const polrCount = 15; // Matches backend
|
| 477 |
|
| 478 |
+
for(let i=0; i<polrCount; i++) {{
|
| 479 |
+
// Calculate opacity: Nearest = 1.0, Furthest = 0.1
|
| 480 |
+
const opacity = 1.0 - (i / (polrCount + 2));
|
| 481 |
+
const color = `rgba(213, 0, 249, ${{opacity.toFixed(2)}})`; // Purple fade
|
| 482 |
+
|
| 483 |
+
polrLines.push(
|
| 484 |
+
priceChart.addLineSeries({{
|
| 485 |
+
color: color,
|
| 486 |
+
lineWidth: 1,
|
| 487 |
+
crosshairMarkerVisible: false,
|
| 488 |
+
lastValueVisible: false,
|
| 489 |
+
priceLineVisible: false,
|
| 490 |
+
title: ''
|
| 491 |
+
}})
|
| 492 |
+
);
|
| 493 |
+
}}
|
| 494 |
+
// --------------------------------
|
| 495 |
|
| 496 |
+
const priceSeries = priceChart.addLineSeries({{ color: '#2979ff', lineWidth: 2, title: 'Price' }});
|
| 497 |
+
const predSeries = priceChart.addLineSeries({{ color: '#ffeb3b', lineWidth: 2, lineStyle: 2, title: 'Math Forecast' }});
|
| 498 |
+
|
| 499 |
const candleChart = LightweightCharts.createChart(document.getElementById('tv-candles'), {{
|
| 500 |
...chartOpts,
|
| 501 |
timeScale: {{ timeVisible: true, secondsVisible: false }}
|
|
|
|
| 543 |
}}
|
| 544 |
}}).observe(document.body);
|
| 545 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 546 |
function connect() {{
|
| 547 |
const ws = new WebSocket((location.protocol === 'https:' ? 'wss' : 'ws') + '://' + location.host + '/ws');
|
| 548 |
|
|
|
|
| 577 |
dom.score.style.color = rho > 0 ? "var(--green)" : (rho < 0 ? "var(--red)" : "var(--text-main)");
|
| 578 |
}}
|
| 579 |
|
| 580 |
+
// 2. Purple River (POLR)
|
| 581 |
+
// We update each line individually based on the received array
|
| 582 |
if (data.polr && data.polr.length) {{
|
| 583 |
+
// We use .update() here to build the history of the prediction lines
|
| 584 |
+
// corresponding to the current time tick
|
| 585 |
+
data.polr.forEach((point, index) => {{
|
| 586 |
+
if (index < polrLines.length) {{
|
| 587 |
+
polrLines[index].update({{
|
| 588 |
+
time: lastTime,
|
| 589 |
+
value: point.p
|
| 590 |
+
}});
|
| 591 |
+
}}
|
| 592 |
+
}});
|
| 593 |
}}
|
| 594 |
}}
|
| 595 |
|