fix: all-local 2-model ensemble (MacBook qwen + GamingPC ornith), no containers, disagreement=SKIP, tight RSI gate with momentum confirmation
This commit is contained in:
40
bot.py
40
bot.py
@@ -342,19 +342,18 @@ def llm_vote(cfg, price, mom, mom_score, conn):
|
||||
except Exception as ex:
|
||||
fast_v, fast_c, fast_w = "BORDERLINE", 0.50, f"gate: {str(ex)[:40]}"
|
||||
|
||||
# ── 3-model ensemble: qwen3.5 (MacBook) + ornith (GPU) + llama3.2 (CT518 diverifier) ──
|
||||
NO_PROXY = {"proxies": {"http": None, "https": None}} # bypass proxy for LAN Ollama calls
|
||||
# ── 2-model ensemble: qwen3.5 (MacBook) + ornith (GamingPC RTX 3070) ──
|
||||
# Disagreement = SKIP (conservative). No diverifier — avoids VRAM contention.
|
||||
NO_PROXY = {"proxies": {"http": None, "https": None}}
|
||||
votes = []
|
||||
# Model 1: qwen3.5 fast gate (MacBook)
|
||||
# Model 1: qwen3.5 fast gate (MacBook — already ran)
|
||||
v1 = fast_v if fast_v in ("UP","DOWN","SKIP") else "SKIP"
|
||||
votes.append((v1, fast_c if fast_v in ("UP","DOWN","SKIP") else 0.50, fast_w, "qwen3.5"))
|
||||
|
||||
# Model 2: ornith deep verify (GamingPC RTX 3070)
|
||||
# Model 2: ornith deep verify (GamingPC RTX 3070 — always hot)
|
||||
try:
|
||||
deep_url = cfg.get("deep_llm_url", "http://10.30.20.186:11434")
|
||||
deep_model = cfg.get("deep_llm_model", "ornith:latest")
|
||||
r2 = requests.post(deep_url+"/api/generate",
|
||||
json={"model": deep_model, "prompt": prompt, "stream": False, "think": False, "keep_alive": "10m",
|
||||
r2 = requests.post("http://10.30.20.186:11434/api/generate",
|
||||
json={"model": "ornith:latest", "prompt": prompt, "stream": False, "think": False, "keep_alive": "10m",
|
||||
"options": {"temperature": 0.2, "num_predict": 90}}, timeout=60, **NO_PROXY)
|
||||
txt2 = r2.json().get("response","")
|
||||
s2, e2 = txt2.find("{"), txt2.rfind("}")+1
|
||||
@@ -366,33 +365,14 @@ def llm_vote(cfg, price, mom, mom_score, conn):
|
||||
LOG.warning(f"ornith failed: {ex2}")
|
||||
votes.append(("SKIP", 0.0, "ornith offline", "ornith"))
|
||||
|
||||
# Model 3: llama3.2 diverifier (CT518) — runs only on disputed signals
|
||||
fast_vote = votes[0][0]; deep_vote = votes[1][0]
|
||||
if fast_vote != deep_vote or (fast_vote in ("UP","DOWN") and votes[0][1] < 0.55):
|
||||
try:
|
||||
div_url = cfg.get("diverify_url", "http://10.30.20.89:11434")
|
||||
div_model = cfg.get("diverify_model", "llama3.2:latest")
|
||||
r3 = requests.post(div_url+"/api/generate",
|
||||
json={"model": div_model, "prompt": prompt, "stream": False, "keep_alive": "10m",
|
||||
"options": {"temperature": 0.3, "num_predict": 60}}, timeout=30, **NO_PROXY)
|
||||
txt3 = r3.json().get("response","")
|
||||
s3, e3 = txt3.find("{"), txt3.rfind("}")+1
|
||||
d3 = json.loads(txt3[s3:e3]) if s3 >= 0 else {}
|
||||
v3 = str(d3.get("vote","SKIP")).upper()
|
||||
if v3 not in ("UP","DOWN","SKIP"): v3 = "SKIP"
|
||||
votes.append((v3, float(d3.get("conf",0)), str(d3.get("why",""))[:120], "llama3.2"))
|
||||
except Exception as ex3:
|
||||
LOG.warning(f"diverifier failed: {ex3}")
|
||||
votes.append(("SKIP", 0.0, "diverifier offline", "llama3.2"))
|
||||
|
||||
# Majority vote: UP vs DOWN vs SKIP counts
|
||||
# Majority: only trade if BOTH agree (2/2). Any disagreement = SKIP.
|
||||
tally = {"UP": 0, "DOWN": 0, "SKIP": 0}
|
||||
for v, c, w, src in votes:
|
||||
tally[v] += 1
|
||||
winner = "UP" if tally["UP"] >= 2 else ("DOWN" if tally["DOWN"] >= 2 else "SKIP")
|
||||
winner = "UP" if tally["UP"] == 2 else ("DOWN" if tally["DOWN"] == 2 else "SKIP")
|
||||
avg_conf = sum(v[1] for v in votes if v[0] == winner) / max(1, tally[winner])
|
||||
reasons = " | ".join(f"{src}={v}" for v, _, _, src in votes)
|
||||
tag = "ENSEMBLE" if tally[winner] >= 2 else "SPLIT"
|
||||
tag = "ENSEMBLE" if winner != "SKIP" else "SPLIT"
|
||||
return winner, avg_conf, f"[{tag}: {tally['UP']}U/{tally['DOWN']}D/{tally['SKIP']}S] {reasons}"
|
||||
|
||||
def decide(cfg, conn, price):
|
||||
|
||||
Reference in New Issue
Block a user