首次上传

This commit is contained in:
dekun
2026-05-16 22:25:48 +08:00
commit 2b8f902548
88 changed files with 16386 additions and 0 deletions
+112
View File
@@ -0,0 +1,112 @@
from __future__ import annotations
import math
from statistics import mean
def rows_to_ohlcv(rows: list[list[str]]) -> tuple[list[float], list[float], list[float], list[float], list[float]]:
o, h, l, c, v = [], [], [], [], []
for item in rows:
if len(item) < 6:
continue
o.append(float(item[1]))
h.append(float(item[2]))
l.append(float(item[3]))
c.append(float(item[4]))
v.append(float(item[5]))
return o, h, l, c, v
def build_daily_programmatic(rows_1d: list[list[str]], est_quote_vol_24h_usdt: float) -> dict:
"""
日线程序化特征:上方空间(距阶段高)、成交活跃度、简单阻力代理(现价与区间高之间局部高点数量)。
"""
_, high, low, close, vol = rows_to_ohlcv(rows_1d)
if len(close) < 10:
return {"error": "insufficient_daily", "have": len(close)}
last = close[-1]
look = min(60, len(close))
hi = max(high[-look:])
lo = min(low[-look:])
mid = (hi + lo) / 2 if hi > lo else last
range_pct = ((hi - lo) / mid) * 100 if mid > 0 else 0.0
upside_pct = ((hi - last) / last) * 100 if last > 0 else 0.0
# 现价上方到区间高:统计「局部高点」数量作为中间阻力代理(越多越密)
seg_h = high[-look:]
seg_l = low[-look:]
local_peaks = 0
for i in range(1, len(seg_h) - 1):
if seg_h[i] >= seg_h[i - 1] and seg_h[i] >= seg_h[i + 1]:
if seg_h[i] > last * 1.002 and seg_h[i] < hi * 0.998:
local_peaks += 1
vol_tail = vol[-20:] if len(vol) >= 20 else vol
vol_mean = mean(vol_tail[:-1]) if len(vol_tail) > 1 else (vol_tail[0] if vol_tail else 1.0)
vol_ratio = (vol_tail[-1] / vol_mean) if vol_mean > 0 else 0.0
sma20 = mean(close[-20:]) if len(close) >= 20 else mean(close)
structure_hint = "price_above_sma20" if last >= sma20 else "price_below_sma20"
return {
"last_close": round(last, 8),
"range_60d_high": round(hi, 8),
"range_60d_low": round(lo, 8),
"range_pct_lookback": round(range_pct, 4),
"upside_to_range_high_pct": round(max(0.0, upside_pct), 4),
"mid_resistance_proxy_peaks": local_peaks,
"volume_last_vs_20d_mean": round(vol_ratio, 4),
"est_quote_vol_24h_usdt": round(est_quote_vol_24h_usdt, 2),
"structure_hint": structure_hint,
"sma20": round(sma20, 8),
}
def programmatic_scores(prog: dict) -> dict:
"""归一化子分数 0100,供合成 composite。"""
if prog.get("error"):
return {"vol": 0.0, "upside": 0.0, "liquidity": 0.0, "mid_clear": 0.0}
est = float(prog.get("est_quote_vol_24h_usdt") or 0.0)
# 成交额:10M≈35100M≈70
vol_score = min(100.0, max(0.0, math.log10(est / 1e6 + 1) * 32.0))
upside = float(prog.get("upside_to_range_high_pct") or 0.0)
upside_score = min(100.0, upside * 4.0)
vr = float(prog.get("volume_last_vs_20d_mean") or 0.0)
liquidity_score = min(100.0, max(0.0, (vr - 1.0) * 35.0 + 40.0))
peaks = int(prog.get("mid_resistance_proxy_peaks") or 0)
mid_clear_score = max(0.0, 100.0 - peaks * 12.0)
return {
"vol": round(vol_score, 2),
"upside": round(upside_score, 2),
"liquidity": round(liquidity_score, 2),
"mid_clear": round(mid_clear_score, 2),
}
def composite_score(gemma_priority: float, sub: dict) -> float:
"""gemma_priority 110;与程序化子分合成 0–100。"""
g = max(1.0, min(10.0, gemma_priority)) * 10.0
p = 0.35 * g
p += 0.2 * sub.get("vol", 0.0)
p += 0.2 * sub.get("upside", 0.0)
p += 0.15 * sub.get("liquidity", 0.0)
p += 0.1 * sub.get("mid_clear", 0.0)
return round(min(100.0, max(0.0, p)), 2)
def daily_ohlc_text_block(rows_1d: list[list[str]], max_lines: int = 24) -> str:
"""给 LLM 的紧凑 OHLCV 文本(时间正序:旧→新,最后一行为最新)。"""
rows = rows_1d[-max_lines:] if len(rows_1d) > max_lines else rows_1d
lines = ["ts,o,h,l,c,vol"]
for item in rows:
if len(item) < 6:
continue
ts, o, h, l, c, v = item[0], item[1], item[2], item[3], item[4], item[5]
lines.append(f"{ts},{o},{h},{l},{c},{v}")
return "\n".join(lines)