Files
gate_scout_order/onchain_scout_gate/app/config.py
T
2026-05-22 22:31:09 +08:00

193 lines
6.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from pathlib import Path
from typing import Literal
import yaml
from pydantic import BaseModel, Field, ValidationError
class AppConfig(BaseModel):
host: str = "0.0.0.0"
port: int = 8088
poll_interval_seconds: int = 120
log_file: str = "./runtime/system.log"
database_url: str = "sqlite+aiosqlite:///./runtime/alerts.db"
session_secret: str = "please-change-me"
class AuthConfig(BaseModel):
"""
enabled: 为 false 时跳过登录(仅建议纯局域网、无外网暴露时使用)。
"""
enabled: bool = True
username: str
password: str
class WeComConfig(BaseModel):
webhook: str
mentioned_mobile_list: list[str] = Field(default_factory=list)
class GateConfig(BaseModel):
"""Gate.io 公共 REST v4USDT 永续 settle=usdt)。"""
api_base: str = "https://api.gateio.ws/api/v4"
settle: str = "usdt"
quote_currency: str = "USDT"
class ProxyConfig(BaseModel):
"""
出站 HTTP 客户端代理(httpx),用于访问 Gate 等外网。
企业微信与本机/局域网 Ollama(Gemma)默认直连,不使用此配置。
可写 socks5h://…;程序在交给 httpx 时会自动改为 socks5://(避免 Unknown scheme)。
"""
enabled: bool = False
url: str = "socks5h://127.0.0.1:1080"
class OrderExecutorConfig(BaseModel):
"""
与 gate_order_executor 联动:企微突破推送 **成功之后**,向执行器 POST /v1/signal。
请求不走 proxy.url(直连 base_url),便于同机 127.0.0.1。
webhook_secret 须与执行器 config.yaml 的 security.webhook_secret 一致。
"""
enabled: bool = False
base_url: str = "http://127.0.0.1:8090"
webhook_secret: str = ""
timeout_seconds: float = Field(15.0, ge=3.0, le=120.0)
class WatchSymbol(BaseModel):
"""Gate USDT 永续 base 资产符号,如 BTC、ORDI、1000PEPE(与合约名 BTC_USDT 的左侧一致)。"""
symbol: str
class KeyMonitorConfig(BaseModel):
"""
人工关键位突破监控(漏斗下方录入)。
触发后按录入的标准/趋势方案计算单一 SL/TP,企微推送并可选转发执行器。
"""
enabled: bool = True
poll_interval_seconds: int = Field(5, ge=2, le=120)
push_wecom: bool = True
forward_executor: bool = True
standard_stop_outside_pct: float = Field(0.3, ge=0.0, le=5.0)
trend_stop_outside_pct: float = Field(1.0, ge=0.0, le=10.0)
min_planned_rr: float = Field(1.5, gt=0.0)
volume_ma_bars: int = Field(20, ge=5)
volume_ratio_min: float = Field(1.3, gt=0.0)
breakout_amp_min_pct: float = Field(0.03, ge=0.0)
breakout_amp_max_pct: float = Field(0.5, gt=0.0)
daily_volume_rank_max: int = Field(30, ge=1)
# 全市场 5m TRIGGER 是否仍转发执行器(默认关;关键位走 forward_executor
auto_scan_forward_executor: bool = False
class MonitorConfig(BaseModel):
"""
监控侧过滤。
universe:
- all_swaps: 监控 Gate 全部 USDT 本位线性永续中,24h 成交额达标的合约(不依赖 watch_symbols)。
- watchlist: 仅监控 watch_symbols 中列出且满足成交额阈值的标的。
min_24h_quote_volume_usdt: 近 24h 成交额下限(USDT)。优先使用 Gate ticker 的 volume_24h_quote。
all_swaps 模式下若设为 0 或负数,将拒绝整轮扫描(避免无阈值拉全市场)。
watchlist 模式下 0 表示关闭成交额过滤。
btc_daily_gate_enabled: 可选;true 时仍计算 BTC 日线 regime 供面板/日志参考,不再拦截山寨扫描。
btc_sideways_lookback_days / btc_sideways_max_range_pct: 与上述辅助门控配套的横盘区分参数。
"""
universe: Literal["all_swaps", "watchlist"] = "all_swaps"
min_24h_quote_volume_usdt: float = 10_000_000
# 可选:BTC 日线 regime 仅展示/记录;推送门控用「近8h×15m BTC 环境(横盘则多空均可;否则涨→LONG、跌→SHORT)+ 本币4h同向」
btc_daily_gate_enabled: bool = True
btc_sideways_lookback_days: int = 14
btc_sideways_max_range_pct: float = 10.0
# 同一币种在 N 小时内对同一条「链路」只落库一条告警、只推送一次(0 表示关闭去重)
# 链路含:GATE-USDT 5m WATCH / GATE-USDT 5m TRIGGER(分级)与 FUNNEL-GEMMA(漏斗)
symbol_signal_dedupe_hours: float = 4.0
# 企业微信主推送(突破预警):仅对本轮监控池内 24h 成交额排名前 N 的合约推送;0 表示不限制
wecom_push_max_volume_rank: int = 30
class GemmaConfig(BaseModel):
"""
Gemma 漏斗:默认直连本机 Ollama/api/chat)。
若使用 OpenAI 兼容网关(如 https://op.bz121.com/v1 + Bearer),设 api_style=openai 并填写 api_key。
"""
enabled: bool = False
ollama_base_url: str = "http://127.0.0.1:11434"
api_key: str = ""
api_style: Literal["ollama", "openai"] = "ollama"
model: str = "gemma2:2b"
timeout_seconds: float = 180.0
temperature: float = 0.15
json_mode: bool = True
send_chart_image: bool = True
max_funnel_per_cycle: int = 12
vision_top_n: int = 4
gemma_push_priority_min: float = 7.0
composite_push_min: float = 72.0
class DailyReportConfig(BaseModel):
"""每日晨报:北京时间定时生成昨天复盘,并可推送企业微信。"""
enabled: bool = True
run_time_cn: str = "08:30"
push_wecom: bool = True
run_on_startup: bool = False
class Settings(BaseModel):
app: AppConfig
auth: AuthConfig
wecom: WeComConfig
gate: GateConfig
proxy: ProxyConfig = Field(default_factory=ProxyConfig)
order_executor: OrderExecutorConfig = Field(default_factory=OrderExecutorConfig)
monitor: MonitorConfig = Field(default_factory=MonitorConfig)
key_monitor: KeyMonitorConfig = Field(default_factory=KeyMonitorConfig)
gemma: GemmaConfig = Field(default_factory=GemmaConfig)
daily_report: DailyReportConfig = Field(default_factory=DailyReportConfig)
watch_symbols: list[WatchSymbol] = Field(default_factory=list)
def load_settings(config_path: str = "config.yaml") -> Settings:
path = Path(config_path).expanduser().resolve()
if not path.exists():
raise FileNotFoundError(
f"配置文件不存在: {path}. 请先复制 config.example.yaml 为 config.yaml 并填写密钥。"
)
raw = yaml.safe_load(path.read_text(encoding="utf-8")) or {}
try:
return Settings.model_validate(raw)
except ValidationError as exc:
raise ValueError(f"配置文件校验失败: {exc}") from exc
# 兼容原 OKX 风格 bar 字符串(映射见 app.gate._to_gate_interval
GATE_BAR_CHOICES: tuple[str, ...] = (
"1m",
"3m",
"5m",
"15m",
"30m",
"1H",
"2H",
"4H",
"6H",
"12H",
"1D",
"1W",
"1M",
)