UI与扩展
策略光有逻辑不够,还得能「看见」。PythonGo 提供了内置 K 线图组件和定时器工具,让策略既能画指标线、又能做定时任务。本章讲 UI 组件怎么接、指标怎么定义、定时器怎么用。
一、带 UI 的策略基类
需要 K 线图的策略,要从 pythongo.ui(而非 pythongo.base)导入 BaseStrategy:
from pythongo.ui import BaseStrategy # 注意是 ui 模块
class DemoKLine(BaseStrategy):
"""带 K 线图的策略"""
...
pythongo.ui.BaseStrategy 继承自 pythongo.base.BaseStrategy,额外内置了 K 线组件 self.widget,并自动处理策略启动时显示窗口、暂停时隐藏窗口的逻辑——你不用手动管 UI 生命周期。
只有不需要 K 线图的策略才用
pythongo.base.BaseStrategy;需要画图就用pythongo.ui。回测时 UI 相关代码会被自动跳过。
二、定义主图与副图指标
指标通过 @property 装饰器定义成属性,框架每次取值都拿最新数据,无需手动赋值:
class DemoKLine(BaseStrategy):
def __init__(self) -> None:
super().__init__()
self.params_map = Params()
self.fast_ma = 0.0
self.slow_ma = 0.0
@property
def main_indicator_data(self) -> dict[str, float]:
"""主图指标——画在 K 线主图上"""
return {
f"MA{self.params_map.fast_period}": self.fast_ma,
f"MA{self.params_map.slow_period}": self.slow_ma,
}
@property
def sub_indicator_data(self) -> dict[str, float]:
"""副图指标——画在 K 线副图上(如 KDJ)"""
return {"K": self.k, "D": self.d, "J": self.j}
要点:
- 属性名固定:主图用
main_indicator_data,副图用sub_indicator_data。 - 返回
dict[str, float],键是指标名(显示在图例上),值是数值。 - 用
f-string配合参数,能让指标名随周期变化(如MA5/MA20),改周期时图例自动更新。 - 不能直接给这两个属性赋值,必须自己定义同名
@property。
三、把数据推给 K 线图
算完指标后,用 self.widget.recv_kline() 把 K 线和指标一起更新到图上:
from pythongo.classdef import KLineData
def callback(self, kline: KLineData) -> None:
"""K 线成型回调"""
self.calc_indicator()
self.widget.recv_kline({
"kline": kline, # K 线数据(必有)
"signal_price": 0.0, # 可选:买卖信号标记价格
**self.main_indicator_data # 解包主图指标
})
def real_time_callback(self, kline: KLineData) -> None:
"""实时回调(每个 tick)——实时更新指标和图"""
self.calc_indicator()
self.widget.recv_kline({"kline": kline, **self.main_indicator_data})
recv_kline 接收一个字典,键包括:kline(K 线对象)、signal_price(信号价格,会在图上标箭头)、以及你解包进去的指标名。
四、定时器 Scheduler
很多策略需要定时任务(开盘下单、收盘平仓、每隔 N 秒检查)。PythonGo 封装了 apscheduler 的 Scheduler:
from datetime import datetime
from pythongo.utils import Scheduler
class MyStrategy(BaseStrategy):
def __init__(self) -> None:
super().__init__()
self.scheduler = Scheduler() # 传入名称即为单例模式
self.scheduler.start()
def on_start(self) -> None:
super().on_start()
# 每隔 30 秒执行一次
self.scheduler.add_job(
func=self.do_something,
trigger="interval",
id="my_job",
seconds=30,
next_run_time=datetime.now() # 立即执行第一次
)
# 每天 14:55 执行
self.scheduler.add_job(
func=self.close_position,
trigger="cron",
id="close_job",
hour=14, minute=55
)
def on_stop(self) -> None:
super().on_stop()
self.scheduler.remove_job("my_job")
def do_something(self) -> None:
self.output("定时任务触发")
def close_position(self) -> None:
self.output("收盘平仓")
三种触发器:
| 触发器 | 含义 | 关键参数 |
|---|---|---|
date | 某个确定时间点运行一次 | run_date |
interval | 固定间隔周期运行 | seconds / minutes / hours |
cron | 按日历周期运行(类似 cron) | hour / minute / day_of_week |
单例模式:
Scheduler("my_name")传入名称后,同名的实例返回同一内存地址,可在多个策略间共享同一个定时器。单例下stop()只移除所有任务,不停止定时器本身。定时器停止后无法重启,需重新实例化。
五、日志与调试
self.output(*msg):输出到 PythonGO 控制台,支持任意类型和参数。CustomLogHandler:第三方库的日志(如它自带logging)默认看不到,用这个 Handler 桥接到 PythonGO 日志系统。
调试时善用 self.output 打印关键变量,配合 state_map 在界面状态栏实时观察数值变化。
小结
用 pythongo.ui.BaseStrategy 获得内置 K 线组件;main_indicator_data / sub_indicator_data 定义主副图指标;
widget.recv_kline() 更新图表;Scheduler 做定时任务。到此,PythonGo 从环境、骨架、行情交易到 UI 扩展形成
完整闭环——左侧导航可随时回查任一章节。