如果说前十一章是对软件操作的指南,相对易于掌握,那么本章将深入到整个系统的核心——策略编写。本章是实现量化交易思想的关键,旨在为开发者提供一个关于”看海量化交易系统”策略框架的直观理解,并详细说明如何基于此框架,一步步构建属于自己的交易策略。我们将重点介绍策略文件的基本结构、核心回调函数,以及与框架交互的关键API。
策略框架是什么
对于每一位交易者而言,心中都有一套独特的交易逻辑。量化交易的本质,便是将这套逻辑转化为代码,让计算机去执行。然而,从零开始编写一套完整的交易程序是复杂且耗时的,需要处理数据获取、订单管理、风险控制、事件驱动等一系列繁琐的底层任务。
策略框架正是为了解决这一问题而生。可以将它理解为一个半成品的交易机器人,它已经为开发者搭建好了坚实的骨架,处理了所有与交易逻辑无关的技术细节。开发者只需要专注于策略本身,将交易思想填充到框架预留的接口中,即可快速构建出功能完备、稳定可靠的自动化交易策略。
为了贴近主流的量化实践和用户习惯,khQuant
定义了一套符合直觉的策略框架。它主要包含四个核心部分,分别对应策略生命周期中的不同阶段:
- 初始化 (
init
): 策略开始运行时,用于进行全局设置,仅执行一次。 - 盘前回调 (
khPreMarket
): 每个交易日开盘前,用于执行每日的准备工作。 - 主回调 (
khHandlebar
): 在盘中根据设定的频率被反复调用,是策略逻辑的核心。 - 盘后回调 (
khPostMarket
): 每个交易日收盘后,用于执行当日的复盘和清理任务。
这四个部分均以函数的形式存在于策略文件中。框架会在特定的时间点自动调用这些函数,并将包含当前市场行情、账户资金、持仓情况等所有必要信息的 context
对象作为参数传递给它们。在函数中完成逻辑判断后,只需返回标准的交易指令(我们称之为”信号”),框架便会自动执行后续的下单操作。这种设计极大地简化了策略编写的复杂度,使开发者可以聚焦于策略逻辑本身,而非底层实现。
12.1 策略框架一览
一个策略文件本质上是一个标准的Python脚本,通过实现框架预定义的一系列函数来完成策略逻辑。以下是一个策略文件的最简化结构,它包含了所有主要的回调函数,可以作为开始编写新策略的模板。
from typing import Dict, List
def init(stock_list, context):
"""
策略初始化函数,在任务开始时仅执行一次。
用于定义全局变量、加载外部数据等。
"""
pass
def khHandlebar(context: Dict) -> List[Dict]:
"""
策略核心逻辑,会被框架根据设定的频率反复调用。
负责行情判断和生成交易信号。
"""
signals = []
return signals
def khPreMarket(context: Dict) -> List[Dict]:
"""
盘前处理函数(可选)。
在每日开盘前的指定时间点调用。
"""
signals = []
return signals
def khPostMarket(context: Dict) -> List[Dict]:
"""
盘后处理函数(可选)。
在每日收盘后的指定时间点调用。
"""
signals = []
return signals
12.2 核心回调函数详解
框架通过在特定时机调用策略文件中的特定函数来驱动策略运行。开发者需要根据需求实现这些函数。为了更好地理解,可以参考我们提供的 strategies/MACD.py
策略示例文件,它展示了如何实现一个完整的策略。
12.2.1 init(stock_list, context)
– 初始化函数
- 执行时机:在整个回测或交易任务开始时,被框架调用一次。
- 核心作用:用于执行策略的全局初始化任务,如设置参数、加载数据等。
- 参数说明:
stock_list
(list): 框架传入的股票池列表,例如['000001.SZ', '600000.SH']
。context
(dict): 一个包含初始化时刻上下文信息的字典。其内部详细结构如下:__current_time__
(dict): 包含当前时间信息的字典。timestamp
: (int) 标准Unix时间戳。datetime
: (str) 格式为 “YYYY-MM-DD HH:MM:SS” 的日期时间字符串。date
: (str) 格式为 “YYYY-MM-DD” 的日期字符串。time
: (str) 格式为 “HH:MM:SS” 的时间字符串。
__account__
(dict): 包含账户资金信息的字典。account_type
: (str) 账户类型 (例如, ‘STOCK’)。account_id
: (str) 账户ID。cash
: (float) 当前可用资金。frozen_cash
: (float) 冻结资金。market_value
: (float) 持仓市值。total_asset
: (float) 总资产。benchmark
: (str) 基准指数代码。
__positions__
(dict): 包含持仓信息的字典,在初始化时通常为空{}
。__framework__
(object): 框架核心类的实例。它包含了最全面的框架信息和功能接口。如果其他上下文参数不包含所需信息,可以尝试通过此对象获取。
12.2.2 khHandlebar(context)
– 策略主逻辑函数
- 执行时机:根据主界面”运行驱动区”设置的触发方式,被框架反复、高频地调用。
- 核心作用:这是实现交易策略核心逻辑的地方,包括行情判断、信号生成、下单等。
- 参数说明:
context
(dict): 包含当前时间点所有可用信息的字典,其结构为:__current_time__
(dict): 包含当前时间信息的字典。timestamp
: (int) 标准Unix时间戳。datetime
: (str) 格式为 “YYYY-MM-DD HH:MM:SS” 的日期时间字符串。date
: (str) 格式为 “YYYY-MM-DD” 的日期字符串。time
: (str) 格式为 “HH:MM:SS” 的时间字符串。
__account__
(dict): 包含账户资金信息的字典。account_type
: (str) 账户类型。account_id
: (str) 账户ID。cash
: (float) 当前可用资金。frozen_cash
: (float) 冻结资金。market_value
: (float) 持仓市值。total_asset
: (float) 总资产。benchmark
: (str) 基准指数代码。
__positions__
(dict): 包含当前持仓信息的字典。其结构为{股票代码: 持仓详情}
。持仓详情是一个字典,包含了该股票的详细持仓信息,其内部字段如下:account_type
: (int) 账户类型。account_id
: (str) 账户ID。stock_code
: (str) 股票代码。volume
: (int) 持仓数量。can_use_volume
: (int) 可用数量(可卖出数量)。open_price
: (float) 当日开盘价。market_value
: (float) 持仓市值。frozen_volume
: (int) 冻结数量。on_road_volume
: (int) 在途数量。yesterday_volume
: (int) 昨日持仓数量。avg_price
: (float) 持仓成本价。current_price
: (float) 当前市价。direction
: (int) 持仓方向。profit
: (float) 持仓浮动盈亏。profit_ratio
: (float) 持仓盈亏率。
__framework__
(object): 框架核心类的实例。它包含了最全面的框架信息和功能接口。如果其他上下文参数不包含所需信息,可以尝试通过此对象获取。[股票代码]
(pandas.Series): 以股票代码(如'000001.SZ'
)为键,值为一个Pandas Series对象,包含了该股票在当前时间点的所有行情字段(如open
,high
,low
,close
,volume
等)。
- 返回值:
- 该函数需要返回一个交易信号列表 (
List[Dict]
)。框架在收到返回的列表后,会自动解析其中的每一条指令,并调用底层的交易接口去执行。如果列表为空,则框架认为当前时间点无任何操作。 - 一个标准的交易信号字典包含以下键值对:
- 该函数需要返回一个交易信号列表 (
键 (Key) | 类型 (Type) | 必填 | 说明 |
---|---|---|---|
code |
str | 是 | 股票代码,必须是标准的QMT格式,例如 '000001.SZ' 或 '600036.SH' 。 |
action |
str | 是 | 交易动作。可选值为 ‘buy’ (买入) 或 ‘sell’ (卖出)。 |
price |
float | 是 | 交易价格。 |
volume |
int | 是 | 交易数量,必须是100的整数倍。 |
reason |
str | 否 | 交易原因或备注。此信息会显示在日志和交易记录中。 |
timestamp |
int | 否 | 信号生成时的时间戳。 |
- 关于信号字典的更详细说明,请参考 12.7 交易信号详解。
12.2.3 khPreMarket(context)
– 盘前处理函数(可选)
- 执行时机:在每个交易日的指定盘前时间点(如09:00)被调用一次。该功能需要在主界面”盘前盘后触发设置”中勾选”触发盘前回调”才会生效。
- 参数
context
:其结构与khHandlebar
函数的context
完全相同。它包含了当天第一个行情数据点的所有信息,包括账户、持仓、以及股票池内所有股票在该时刻的行情数据。 - 返回值:与
khHandlebar
类似,返回一个交易信号列表 (List[Dict]
)。 - 常见用途:
- 每日选股、计算因子。
- 重置当日的交易状态或计数器。
- 提前下达一些集合竞价阶段的预埋单。
12.2.4 khPostMarket(context)
– 盘后处理函数(可选)
- 执行时机:在每个交易日的指定盘后时间点(如15:30)被调用一次。该功能需要在主界面”盘前盘后触发设置”中勾选”触发盘后回调”才会生效。
- 参数
context
:其结构与khHandlebar
函数的context
完全相同。它包含了当天最后一个行情数据点的所有信息,包括账户、持仓、以及股票池内所有股票在该时刻的行情数据。 - 返回值:与
khHandlebar
类似,返回一个交易信号列表 (List[Dict]
)。 - 常见用途:
- 当日交易复盘、业绩归因分析。
- 保存当日的策略状态或数据到本地文件。
- 清理当日持仓,或为下一个交易日做准备。
12.3 获取时间数据
在策略中,所有时间相关的信息都储存在 context['__current_time__']
这个字典中。通过访问它,可以获取到策略当前执行点的精确时间。
context['__current_time__']['timestamp']
: 返回一个整数形式的Unix时间戳。context['__current_time__']['datetime']
: 返回YYYY-MM-DD HH:MM:SS
格式的字符串,最常用。context['__current_time__']['date']
: 返回YYYY-MM-DD
格式的日期字符串。context['__current_time__']['time']
: 返回HH:MM:SS
格式的时间字符串。
示例:实现简单的择时逻辑
def khHandlebar(context: Dict) -> List[Dict]:
time_info = context['__current_time__']
# 获取当前时间字符串,如 '09:31:00'
current_time = time_info['time']
# 简单的交易时间控制:只在上午10点后、下午2点半前进行交易判断
if "10:00:00" < current_time < "14:30:00":
# 在这里编写主要的策略逻辑...
print("处于交易时间段,执行策略。")
else:
# 非交易时间段,不执行任何操作
print("非交易时间段,跳过。")
return []
12.4 获取账户数据
账户的资金状况信息储存在 context['__account__']
字典中,它提供了账户资产的实时快照。
context['__account__']['cash']
: (float) 当前可用于交易的现金。context['__account__']['market_value']
: (float) 所有持仓按当前市价计算的总市值。context['__account__']['total_asset']
: (float) 总资产,即cash
+market_value
。context['__account__']['frozen_cash']
: (float) 因挂单而冻结的资金。
示例:根据资金动态计算买入量
def khHandlebar(context: Dict) -> List[Dict]:
account = context['__account__']
# 获取当前可用资金
available_cash = account['cash']
# 设定一个目标仓位:使用当前可用资金的20%
cash_to_use = available_cash * 0.2
# 获取 '000001.SZ' 的当前价格
stock_data = context.get('000001.SZ')
if stock_data is not None and not stock_data.empty:
stock_price = stock_data['close']
# 计算理论上可以买入多少股,并向下取整到100的倍数
if stock_price > 0:
volume_to_buy = int(cash_to_use / stock_price / 100) * 100
if volume_to_buy > 0:
print(f"资金充足,计划以 {stock_price} 元的价格买入 {volume_to_buy} 股 000001.SZ")
# 此处可以构建并返回一个买入信号
return []
12.5 获取持仓数据
持仓信息 context['__positions__']
是一个字典,键为股票代码,值为该股票的详细持仓信息字典。这使得检查特定持仓、获取持仓细节变得非常方便。
示例:实现持仓股票的止盈止损
def khHandlebar(context: Dict) -> List[Dict]:
positions = context['__positions__']
signals = []
# 检查是否持有 '600519.SH' (贵州茅台)
if '600519.SH' in positions:
# 获取该持仓的详细信息
pos_info = positions['600519.SH']
volume = pos_info['volume']
profit_ratio = pos_info['profit_ratio'] # 获取持仓盈亏率
print(f"持有 {volume} 股 600519.SH,当前盈利 {profit_ratio*100:.2f}%")
# 止盈逻辑:如果盈利超过10%,就全部卖出
if profit_ratio > 0.10:
sell_signal = {
'action': 'sell',
'code': '600519.SH',
'volume': volume, # 卖出全部持仓
'remark': '盈利超过10%,止盈'
}
signals.append(sell_signal)
# 止损逻辑:如果亏损超过5%,就全部卖出
elif profit_ratio < -0.05:
sell_signal = {
'action': 'sell',
'code': '600519.SH',
'volume': volume, # 卖出全部持仓
'remark': '亏损超过5%,止损'
}
signals.append(sell_signal)
return signals
12.6 获取当前运行配置
在某些复杂的策略场景中,可能需要在策略逻辑内部获取在GUI界面上配置的参数,例如获取设置的基准合约代码,或者根据不同的手续费配置调整交易行为。
这些配置信息可以通过 context
中的 __framework__
对象进行访问。
context['__framework__'].config
: 这是一个khConfig.KhConfig
类的实例,持有本次运行的所有配置信息。
示例:在策略中获取基准合约和手续费配置
def init(stock_list, context):
# 从框架对象中获取配置实例
config = context['__framework__'].config
# 读取回测配置中的 'benchmark' 参数
benchmark_code = config.get_config('backtest.benchmark')
print(f"当前配置的基准合约为: {benchmark_code}")
# 读取交易成本中的佣金比例
commission_rate = config.get_config('backtest.trade_cost.commission_rate')
print(f"当前配置的佣金比例为: {commission_rate}")
12.7 交易信号详解
交易信号是策略与交易执行模块沟通的唯一方式。它是一个包含了所有交易必要信息的Python字典。khHandlebar
、khPreMarket
、khPostMarket
的返回值以及__framework__.trade()
的参数都是交易信号。
一个标准的交易信号字典包含以下键值对:
键 (Key) | 类型 (Type) | 必填 | 说明 |
---|---|---|---|
code |
str | 是 | 股票代码,必须是标准的QMT格式,例如'000001.SZ' 或 '600036.SH' 。 |
action |
str | 是 | 交易动作。可选值为 ‘buy’ (买入) 或 ‘sell’ (卖出)。 |
price |
float | 是 | 交易价格。 |
volume |
int | 是 | 交易数量,必须是100的整数倍。 |
reason |
str | 否 | 交易原因或备注。此信息会显示在日志和交易记录中。 |
timestamp |
int | 否 | 信号生成时的时间戳。 |
示例:
# 以10.5元的价格买入100股平安银行
signal_1 = {
'code': '000001.SZ',
'action': 'buy',
'price': 10.5,
'volume': 100,
'reason': 'MACD金叉买入'
}
# 以18.5元的价格卖出200股贵州茅台
signal_2 = {
'code': '600519.SH',
'action': 'sell',
'price': 18.50,
'volume': 200,
'reason': '达到止盈位卖出'
}
12.8 在策略中使用日志
为了方便调试和监控策略的内部状态,可以在策略代码中直接调用日志输出功能,将信息发送到看海量化交易系统的日志系统(包括界面和文件)。
核心机制:框架已经对Python内置的 logging
模块进行了配置。因此,开发者无需关心日志的底层实现,只需在策略代码中导入 logging
模块,然后直接调用其标准函数即可。
使用方法:
- 在策略文件顶部添加
import logging
。 - 在代码中调用
logging.info()
,logging.warning()
,logging.error()
等函数。
日志级别与界面上显示的颜色直接对应:
- 普通信息 (INFO): 使用
logging.info("进入长仓条件判断")
输出常规的流程信息或变量状态。这对应界面上的 白色 文本。 - 调试信息 (DEBUG): 如果需要输出更详细的、仅在调试时关心的变量值或中间计算结果,可以使用
logging.debug(f"当前ATR值: {atr_value}")
。这对应界面上的 浅紫色 文本。(注意:默认配置下,DEBUG级别的日志可能不会显示,需在设置中调整) - 警告信息 (WARNING): 当策略遇到一些非致命但需要注意的情况时,比如某个数据获取失败但有备用方案,可以使用
logging.warning("无法获取最新行情,使用上一周期数据代替")
。这对应界面上的 橙色 文本,比较醒目。 - 错误信息 (ERROR): 当策略发生严重错误,可能导致后续逻辑无法正常执行时,应使用
logging.error("计算指标时出现除零错误")
。这对应界面上最醒目的 红色 文本,强烈提示需要检查问题。
示例:
import logging
from typing import Dict, List
def khHandlebar(context: Dict) -> List[Dict]:
# 检查账户现金
cash = context['__account__']['cash']
logging.info(f"当前可用资金: {cash}")
if cash < 10000:
logging.warning("可用资金不足1万元,跳过本次交易机会。")
return []
# ...后续策略逻辑...
try:
# 可能会出错的代码
risky_value = 1 / 0
except Exception as e:
logging.error(f"计算风险值时发生严重错误: {e}", exc_info=True) # exc_info=True会记录完整的错误堆栈
return []
如何输出醒目的内容?
如果希望某条日志信息在界面上特别突出,最直接的方式是使用 logging.warning()
或 logging.error()
。ERROR
级别(红色)最为醒目,通常用于指示发生了必须处理的问题。WARNING
级别(橙色)也比较突出,适合用于提示潜在风险或需要关注的状态。请根据信息的重要性和紧急程度,审慎选择合适的级别进行输出。
12.9 策略工具箱:khQTTools
模块详解
为了进一步简化策略开发,khQuant
提供了一个名为 khQTTools.py
的工具模块,其中包含了一系列高效实用的辅助函数。这些工具涵盖了时间判断、交易计算、数据获取等多个方面,能够帮助开发者快速实现复杂的逻辑,避免重复造轮子。
要使用这些工具,只需在策略文件的顶部从 khQTTools
模块导入所需的函数即可。
# 在策略文件顶部导入工具函数
from khQTTools import (
KhQuTools,
calculate_max_buy_volume,
generate_signal,
get_stock_names,
khHistory
)
12.9.1 时间工具 (KhQuTools
)
KhQuTools
是一个封装了常用时间判断功能的类。使用前需要先进行实例化。
# 在init函数或策略的全局部分实例化
tools = KhQuTools()
is_trade_time()
- 功能:判断当前时间是否处于A股的常规交易时间段内(09:30-11:30, 13:00-15:00)。
- 返回值:
bool
,是则返回True
,否则返回False
。 - 使用场景:确保交易逻辑只在开盘时段执行。
示例:
def khHandlebar(context: Dict) -> List[Dict]:
if not tools.is_trade_time():
return [] # 非交易时间,直接返回
# ... 在此编写交易时间内的策略逻辑 ...
logging.info("交易时间内,执行策略。")
return []
is_trade_day(date_str)
- 功能:判断指定日期是否为A股的交易日(会剔除周末和法定节假日)。
- 参数:
date_str
(str, 可选):YYYY-MM-DD
格式的日期字符串。如果留空,则默认判断当天。
- 返回值:
bool
,是交易日则返回True
,否则返回False
。
示例:
# 判断2024年10月1日是否是交易日
is_trading = tools.is_trade_day("2024-10-01")
print(f"2024-10-01 是交易日吗? {'是' if is_trading else '否'}")
# 判断今天是否是交易日
is_today_trading = tools.is_trade_day()
print(f"今天是交易日吗? {'是' if is_today_trading else '否'}")
get_trade_days_count(start_date, end_date)
- 功能:计算两个日期之间的A股交易日天数。
- 参数:
start_date
(str):YYYY-MM-DD
格式的开始日期。end_date
(str):YYYY-MM-DD
格式的结束日期。
- 返回值:
int
,两个日期之间的交易日总数。
示例:
# 计算2024年全年的交易日天数
days = tools.get_trade_days_count("2024-01-01", "2024-12-31")
print(f"2024年共有 {days} 个交易日。")
12.9.2 交易辅助函数
calculate_max_buy_volume(data, stock_code, price, cash_ratio)
- 功能:一个非常实用的函数,用于根据可用资金和股价,计算出理论上可以买入的最大股票数量(会自动向下取整到100的倍数)。
- 参数:
data
(dict): 即策略回调函数中的context
对象。stock_code
(str): 计划买入的股票代码。price
(float): 计划买入的价格。cash_ratio
(float, 可选): 计划使用的资金比例,默认为1.0
(即全部可用资金)。
- 返回值:
int
,可以买入的最大股数。
示例:
def khHandlebar(context: Dict) -> List[Dict]:
# 计划用50%的资金买入平安银行
stock_to_buy = '000001.SZ'
current_price = context.get(stock_to_buy)['close'] # 获取当前价
# 计算最多能买多少股
max_volume = calculate_max_buy_volume(context, stock_to_buy, current_price, cash_ratio=0.5)
if max_volume > 0:
logging.info(f"资金足够,计划以 {current_price} 的价格买入 {max_volume} 股 {stock_to_buy}")
# ...后续可以生成并返回交易信号
return []
generate_signal(data, stock_code, price, ratio, action, reason)
- 功能:高级信号生成函数。对于买入操作,它会自动计算最大可买股数;对于卖出操作,它会自动计算最大可卖股数。极大简化了信号的创建过程。
- 参数:
data
(dict): 即context
对象。stock_code
(str): 交易的股票代码。price
(float): 交易价格。ratio
(float): 比例。当action
为'buy'
时,这是资金使用比例;当action
为'sell'
时,这是持仓卖出比例。action
(str): 交易动作,'buy'
或'sell'
。reason
(str, 可选): 交易原因。
- 返回值:
List[Dict]
,一个包含单个交易信号的列表,如果条件不满足(如无钱可买或无仓可卖),则返回空列表。
示例:
def khHandlebar(context: Dict) -> List[Dict]:
signals = []
# 假设 is_rsi_low 和 is_rsi_high 是已经计算好的布尔值
is_rsi_low = True
is_rsi_high = True
# 1. 如果RSI指标小于30,使用30%的资金买入平安银行
if is_rsi_low and '000001.SZ' in context:
# 只需指定买入比例,函数会自动计算股数
buy_signals = generate_signal(context, '000001.SZ', price=context.get('000001.SZ')['close'], ratio=0.3, action='buy', reason='RSI < 30')
signals.extend(buy_signals)
# 2. 如果持有茅台,且RSI指标大于70,卖出50%的仓位
if '600519.SH' in context['__positions__'] and is_rsi_high:
# 只需指定卖出比例,函数会自动计算股数
sell_signals = generate_signal(context, '600519.SH', price=context.get('600519.SH')['close'], ratio=0.5, action='sell', reason='RSI > 70')
signals.extend(sell_signals)
return signals
12.9.3 数据获取与处理
khHistory(symbol_list, fields, bar_count, fre_step, current_time=None, skip_paused=False, fq='pre', force_download=False)
- 功能:(核心功能) 获取指定证券的历史K线数据,是计算各种技术指标的基础。
-
入口参数 (Input):
symbol_list
(list): 证券代码列表。必须是包含标准QMT格式(如'600000.SH'
)的字符串列表。fields
(list): 希望获取的行情字段列表。常用的字段包括'time'
,'open'
,'high'
,'low'
,'close'
,'volume'
(成交量),'amount'
(成交额)。返回的DataFrame将包含这些列。bar_count
(int): 希望获取的K线数量。例如,bar_count=30
和fre_step='1d'
将获取过去30个交易日的日K线数据。fre_step
(str): K线周期。支持'1m'
,'5m'
,'15m'
,'30m'
,'60m'
等分钟线周期,以及'1d'
(日线),'1w'
(周线),'1mon'
(月线)。current_time
(str, 可选): 获取历史数据的结束时间点,格式为'YYYYMMDDHHMMSS'
。如果设为None
或不提供,则数据截止到当前最新时间。这对于回测中模拟特定时间点的情景非常重要。skip_paused
(bool, 可选): 是否跳过停牌日。默认为False
。如果设为True
,返回的bar_count
根K线将不包含该股票的停牌日,K线是连续的。fq
(str, 可选): 复权类型。默认为'pre'
(前复权)。可选值为'back'
(后复权) 或'none'
(不复权)。force_download
(bool, 可选): 是否强制从远程服务器下载新数据,忽略本地缓存。默认为False
。在进行数据补全或怀疑本地数据有误时,可设为True
。
- 输出参数 (Output):
- 返回值: 一个Python字典。
- 字典结构:
- 键 (Key): 股票代码字符串 (e.g.,
'000001.SZ'
)。 - 值 (Value): 一个
pandas.DataFrame
对象,或者在获取失败时为None
。
- 键 (Key): 股票代码字符串 (e.g.,
- DataFrame结构:
- 索引 (Index): 默认的整数索引。
- 列 (Columns): 与输入的
fields
参数完全对应。例如,如果fields=['time', 'open', 'close']
,DataFrame就会有这三列。time
列是datetime
对象,方便进行时间序列分析。
示例:在 init
中预加载数据,在 khHandlebar
中计算5日均线
import pandas as pd
import logging
from khQTTools import khHistory
# 在全局范围定义一个缓存,用于存储计算好的指标
g = {'sma5': {}}
def init(stock_list, context):
"""
在初始化时,一次性获取所有股票过去30天的日线数据,用于后续计算。
"""
logging.info("开始获取历史数据用于初始化...")
history_data = khHistory(
symbol_list=stock_list,
fields=['time', 'open', 'close'],
bar_count=30,
fre_step='1d'
)
for stock in stock_list:
df = history_data.get(stock)
if df is not None and not df.empty:
# 计算5日均线并存入全局缓存
g['sma5'][stock] = df['close'].rolling(window=5).mean().iloc[-1]
logging.info(f"{stock} 的初始5日均线值为: {g['sma5'][stock]}")
def khHandlebar(context: Dict) -> List[Dict]:
signals = []
# 假设股票池里有 '000001.SZ'
stock_code = '000001.SZ'
if stock_code in context:
current_price = context.get(stock_code)['close']
sma5_value = g['sma5'].get(stock_code)
if sma5_value and current_price > sma5_value:
logging.info(f"{stock_code} 当前价格上穿5日线,产生买入信号。")
# 此处可构建买入信号
# 注意:在实盘中,需要每日更新缓存的指标值,可以在khPreMarket中实现
return signals
get_stock_names(stock_codes, stock_list_file)
- 功能:根据股票代码列表,查询并返回对应的股票名称。
- 参数:
stock_codes
(list/str): 一个或多个股票代码。stock_list_file
(str): 包含股票代码和名称映射关系的CSV文件路径。通常是data/stock_list.csv
。
- 返回值:一个字典,键为股票代码,值为股票名称。
示例:
# 假设 stock_list.csv 在 data 目录下
stock_list_path = "data/stock_list.csv"
names_dict = get_stock_names(['000001.SZ', '600519.SH'], stock_list_path)
# 返回: {'000001.SZ': '平安银行', '600519.SH': '贵州茅台'}
print(names_dict)