Comprehensive fix: live node resilience + CSS contrast + win_rate + equity curves

- Mainnet API fallback when testnet unavailable (prices, orderbook, instruments)
- Bypassed broken SDK instrument loading, uses raw mainnet meta API
- Dynamic BTC/ETH perp ID lookup (handles "-USD-PERP" suffix changes)
- Strategy-level equity tracking for per-strategy detail charts
- Win rate fixed: checks pnl_net/pnl_gross not just pnl field
- CSS contrast improved: --tx #6b6b7b→#9e9eae, borders/highlights brightened
- Equity curve recalculated on fee tier change (chart adjusts visually)
- Added Open Positions & Orders panel placeholder
This commit is contained in:
ramseshk
2026-08-05 02:53:31 +00:00
parent f45417c105
commit 4457cdffc5
5 changed files with 706 additions and 251 deletions
+58 -6
View File
@@ -26,6 +26,7 @@ log = logging.getLogger("ftdt-quant")
METRICS_FILE = "/tmp/ftdt-metrics.json"
TESTNET_API = "https://api.hyperliquid-testnet.xyz/info"
MAINNET_INFO = "https://api.hyperliquid.xyz/info"
TOTAL_EQUITY = 898.0
RESERVE = 398.0
MAKER_FEE = 0.0002
@@ -42,6 +43,7 @@ STRATEGIES = {
trades_log: list[dict] = []
equity_history: list[dict] = []
strategy_equity: dict[str, list] = {}
seen_fills: set[int] = set()
btc_prices: deque = deque(maxlen=60)
eth_prices: deque = deque(maxlen=60)
@@ -97,7 +99,9 @@ def write_metrics(addr):
"total_equity":TOTAL_EQUITY+total_pnl,"base_equity":TOTAL_EQUITY,
"total_pnl":total_pnl,"total_pnl_pct":total_pnl_pct,
"reserve":RESERVE,"equity_history":equity_history[-600:],
"strategies":STRATEGIES,"trades":trades_log[-200:],"status":"running"
"strategies":STRATEGIES,"trades":trades_log[-200:],"status":"running",
"strategy_equity":{k: v[-600:] for k,v in strategy_equity.items()},
"open_positions":[],"open_orders":[]
}
try:
with open(METRICS_FILE,"w") as f: json.dump(data,f,default=str)
@@ -168,10 +172,48 @@ async def main():
addr = client.get_user_address()
client.set_account_id("HYPERLIQUID-"+addr)
insts = await client.load_instrument_definitions(include_perps=True)
perps = {str(i.id.symbol): i for i in insts if "PERP" in str(i.id.symbol)}
for inst in perps.values(): client.cache_instrument(inst)
btc_perp = perps["BTC-USD-PERP"]; eth_perp = perps["ETH-USD-PERP"]
# Load instrument definitions — try testnet SDK first, fallback to raw APIs
insts = []; perps = {}
try:
insts = await client.load_instrument_definitions(include_perps=True)
perps = {str(i.id.symbol): i for i in insts if "PERP" in str(i.id.symbol)}
for inst in perps.values(): client.cache_instrument(inst)
except Exception as e:
log.warning(f"SDK instrument load failed: {e}")
# Fallback: load from raw API (mainnet) if SDK failed or returned empty
if not perps:
log.info("Loading perps from mainnet API directly...")
try:
meta_r = requests.post(MAINNET_INFO, json={"type":"meta"}, timeout=10)
meta = meta_r.json()
for asset in meta.get("universe", []):
name = asset.get("name", "")
if name:
# Build a minimal perp-like object for our purposes
perps[name] = type('Perp', (), {
'id': type('ID', (), {'symbol': name})(),
'base': name,
'quote': 'USD',
})()
log.info(f"Loaded {len(perps)} perps from mainnet meta")
except Exception as e:
log.error(f"Mainnet meta fallback failed: {e}")
if perps:
log.info(f"Perps available: {list(perps.keys())[:10]}...")
else:
log.error("No perps loaded — cannot continue")
sys.exit(1)
# Find BTC/ETH perps dynamically (testnet IDs may differ from mainnet)
btc_perp = None; eth_perp = None
for k, v in perps.items():
ku = k.upper()
if btc_perp is None and ("BTC" in ku):
btc_perp = v
if eth_perp is None and ("ETH" in ku):
eth_perp = v
if not btc_perp or not eth_perp:
log.error(f"Could not find BTC/ETH perps. Available: {list(perps.keys())[:10]}")
sys.exit(1)
prices = get_mark_prices()
btc_bid, btc_ask, btc_mid = get_orderbook("BTC")
@@ -201,6 +243,7 @@ async def main():
log.info(f"Tracking {len(seen_fills)} existing fills")
for s in STRATEGIES.values(): s["status"]="running"
for name in STRATEGIES: strategy_equity[name]=[]
write_metrics(addr)
tick=0; names=list(STRATEGIES.keys()); idx=0
@@ -233,6 +276,7 @@ async def main():
STRATEGIES[strat]["fee_paid"]+=abs(fee)
if closed_pnl>0: STRATEGIES[strat]["wins"]+=1
STRATEGIES[strat]["pnl_pct"]=STRATEGIES[strat]["pnl"]/STRATEGIES[strat]["allocation"]*100
strategy_equity[strat].append({"t":time.time(),"v":STRATEGIES[strat]["allocation"]+STRATEGIES[strat]["pnl"]})
trades_log.append({"time":datetime.now().strftime("%H:%M:%S"),"strategy":strat,"side":"BUY" if side=="B" else "SELL","size":sz,"price":px,"pnl":round(net,4),"fee":round(abs(fee),4)})
new_fills+=1
@@ -242,7 +286,15 @@ async def main():
# Place/refresh orders every 3-5 ticks
if tick>=3 and tick%random.randint(3,5)==0:
btc_bid, btc_ask, btc_mid = get_orderbook("BTC")
eth_bid, eth_ask, eth_mid = get_orderbook("ETH")
try:
btc_bid, btc_ask, btc_mid = get_orderbook("BTC")
except Exception as e:
log.debug(f"OB BTC error: {e}")
btc_bid = btc_ask = btc_mid = 0
try:
eth_bid, eth_ask, eth_mid = get_orderbook("ETH")
except Exception as e:
eth_bid = eth_ask = eth_mid = 0
name = names[idx%7]; idx+=1; cfg=STRATEGIES[name]
coin="BTC" if "BTC" in cfg["instrument"] else "ETH"