Fix dashboard backtest detail, deterministic backtest seeds, paper trader fees, live node crash guard
Backtest detail: openDetail() now fetches full backtest JSON from the API instead of showing "Full trade data not in summary". Renders equity curve chart + full trade history table with 100 rows. Backtest reproducibility: replaced hash(key) with fixed per-strategy seeds. Python's hash() is randomized per process (PYTHONHASHSEED), causing wildly different results for same strategy across runs. Now deterministic. Server: added total_trades and sortino to /api/backtests summary response. Paper trader: fixed Avellaneda-Stoikov simulate using TAKER_FEE instead of MAKER_FEE. Lowered OBI signal threshold from 5bps to 1.5bps for flat markets. Live node: added None-guard in get_mark_prices — Hyperliquid testnet API sometimes returns null, crashing the node. Wrapped in try/except.
This commit is contained in:
+12
-5
@@ -64,11 +64,18 @@ def get_fills(addr):
|
||||
return r.json() if r.status_code==200 else []
|
||||
|
||||
def get_mark_prices():
|
||||
r = requests.post(TESTNET_API, json={"type":"metaAndAssetCtxs"}, timeout=10)
|
||||
data = r.json(); prices = {}
|
||||
for i,u in enumerate(data[0]["universe"]):
|
||||
if u["name"] in ("BTC","ETH"): prices[u["name"]] = float(data[1][i]["markPx"])
|
||||
return prices
|
||||
try:
|
||||
r = requests.post(TESTNET_API, json={"type":"metaAndAssetCtxs"}, timeout=10)
|
||||
data = r.json()
|
||||
if not data or data[0] is None or "universe" not in data[0]:
|
||||
return {}
|
||||
prices = {}
|
||||
for i,u in enumerate(data[0]["universe"]):
|
||||
if u["name"] in ("BTC","ETH"):
|
||||
prices[u["name"]] = float(data[1][i]["markPx"])
|
||||
return prices
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
def get_orderbook(coin):
|
||||
"""Get best bid, best ask, and mid from L2 orderbook."""
|
||||
|
||||
@@ -226,12 +226,12 @@ def compute_signals():
|
||||
if len(btc_prices) < 20: return
|
||||
btc = btc_prices[-1]; eth = eth_prices[-1] if eth_prices else btc/34
|
||||
|
||||
# OFI
|
||||
# Order Book Imbalance — 5-tick price momentum (1.5 bps threshold for flat markets)
|
||||
if len(btc_prices) >= 5:
|
||||
ret = (btc - btc_prices[-5]) / btc_prices[-5]
|
||||
if ret > 0.0005:
|
||||
if ret > 0.00015:
|
||||
STRATEGIES["Order Book Imbalance"]["signals"].append({"time":time.time(),"signal":"SELL","strength":ret})
|
||||
elif ret < -0.0005:
|
||||
elif ret < -0.00015:
|
||||
STRATEGIES["Order Book Imbalance"]["signals"].append({"time":time.time(),"signal":"BUY","strength":abs(ret)})
|
||||
|
||||
# Iceberg
|
||||
@@ -406,7 +406,7 @@ def simulate_avellaneda(btc_bid, btc_ask):
|
||||
side = "BUY" if cfg["position"] <= 0 else "SELL"
|
||||
sz = cfg["size"]
|
||||
notional = sz * bid_fill_price
|
||||
fee = notional * TAKER_FEE
|
||||
fee = notional * MAKER_FEE # A-S is a MAKER strategy — pay maker fee, not taker
|
||||
spread_profit = sz * (btc_ask - btc_bid)/2 if side == "BUY" else 0
|
||||
|
||||
if side == "BUY":
|
||||
|
||||
Reference in New Issue
Block a user