Speed bot v1: REST polling, MLX model, standardized across all infra. WebSocket WIP.

This commit is contained in:
drjones
2026-08-04 00:22:00 -07:00
parent 8ea924f965
commit 2f0e2333df
23 changed files with 285 additions and 29 deletions

View File

@@ -18,7 +18,7 @@ MODEL = "qwen3.5:4b-mlx"
# ── Auth (RSA-PSS-SHA256, same as existing bot) ──
KEY_PATH = os.path.expanduser("~/kalshi-bot/kalshi_private_key.pem")
KEY_ID = "28d5876b"
KEY_ID = "28d5876b-2ece-4aa3-aa17-ec96e1e706eb"
with open(KEY_PATH, "rb") as f:
PK = serialization.load_pem_private_key(f.read(), password=None)
@@ -62,6 +62,7 @@ Vote UP DOWN or SKIP. Respond ONLY with JSON: {{"vote":"UP|DOWN|SKIP","conf":0.0
try:
r = requests.post(f"{OLLAMA_URL}/api/generate",
json={"model": MODEL, "prompt": prompt, "stream": False,
"think": False,
"options": {"temperature": 0.15, "num_predict": 40}},
timeout=8, proxies={"http": None, "https": None})
txt = r.json().get("response", "")
@@ -231,33 +232,52 @@ class SpeedBot:
def run(self):
self.running = True
print(f"[speed-{self.coin}] Starting speed bot (dry_run={self.dry_run}, model={MODEL})")
last_tick_ts = 0
print(f"[speed-{self.coin}] Starting (dry_run={self.dry_run}, model={MODEL}, REST mode)")
# Warm the MLX model
try:
requests.post(f"{OLLAMA_URL}/api/generate",
json={"model": MODEL, "prompt": "hi", "stream": False,
"think": False, "keep_alive": "30m",
"options": {"num_predict": 5}},
timeout=30, proxies={"http": None, "https": None})
print(f"[speed-{self.coin}] MLX model warm")
except Exception:
pass
while self.running:
try:
self.ws = websocket.WebSocketApp(
KALSHI_WS,
header=self._ws_headers(),
on_open=self.on_open,
on_message=self.on_message,
on_error=self.on_error,
on_close=self.on_close,
)
self.ws.run_forever(ping_interval=30, ping_timeout=10)
# REST polling (WebSocket auth WIP)
markets = get_open_markets()
our_markets = [m for m in markets if self.coin in m.get("ticker", "")]
for mkt in our_markets[:1]: # Trade the first open market
ticker = mkt["ticker"]
mkt_data = get_ticker(ticker)
mkt_data = mkt_data.get("market", mkt_data)
price = float(mkt_data.get("last_price", 0) or mkt_data.get("yes_bid", 0) or 0)
if price > 0:
self.prices.append(price)
self.db.execute("INSERT INTO ticks VALUES (?,?,?)",
(time.time(), price, mkt_data.get("volume", 0) or 0))
self.db.commit()
# Decision check
now = time.time()
if now - self.last_decision >= self.decision_cooldown and len(self.prices) >= 20:
self.last_decision = now
self._decide(ticker, price)
time.sleep(5) # Poll every 5 seconds
except Exception as e:
print(f"[speed-{self.coin}] Reconnecting in 5s: {e}")
print(f"[speed-{self.coin}] Loop error: {e}")
time.sleep(5)
def _ws_headers(self):
ts = str(int(time.time() * 1000))
path = "/trade-api/ws/v2"
msg = f"{ts}GET{path}".encode()
sig = base64.b64encode(hmac.HMAC(KEY, msg, hashlib.sha256).digest()).decode()
return {
"KALSHI-ACCESS-KEY": KEY_ID,
"KALSHI-ACCESS-SIGNATURE": sig,
"KALSHI-ACCESS-TIMESTAMP": ts,
}
return sign("GET", "/trade-api/ws/v2")
if __name__ == "__main__":