量化:KDJ策略

1 什么是KDJ策略

KDJ 是⼀种技术分析指标,常⽤于股票市场和其他⾦融市场中,⽤来辅助判断市场的超买和超
卖状态,以及趋势的强弱。KDJ 指标基于随机指标(Stochastic Oscillator)进⾏改进,它包括三
条线,分别是 K 线、D 线和 J 线。

2 知识储备

set_order_cost() 设置佣⾦/印花税

  1. set_order_cost(cost, type, ref=None)
  2. 指定每笔交易要收取的⼿续费, 系统会根据⽤户指定的费率计算每笔交易的⼿续费

参数

  • cost: OrderCost 对象

  • open_tax,买⼊时印花税 (只股票类标的收取,基⾦与期货不收)

  • close_tax,卖出时印花税 (只股票类标的收取,基⾦与期货不收)

  • open_commission,买⼊时佣⾦

  • close_commission, 卖出时佣⾦

  • close_today_commission, 平今仓佣⾦

  • min_commission, 最低佣⾦,不包含印花税

  • type: 股票、场内基⾦、场内交易的货币基⾦、分级A基⾦、分级B基⾦、分级⺟基⾦、⾦融期货、期货、债券基⾦、股票基⾦、QDII 基⾦、混合基⾦,'stock'/ 'fund' / 'mmf' /'fja'/'fjb'/ 'fjm'/'index_futures' / 'futures' / 'bond_fund' / 'stock_fund' / 'QDII_fund' / / 'mixture_fund' /

  • ref: 参考代码,⽀持股票代码/基⾦代码/期货合约代码,以及期货的品种,如'000001.XSHE'/'510180.XSHG'/'IF1709'/'IF'/'000300.OF'
    注意:针对特定的交易品种类别设置⼿续费时,必须将ref设为None;若针对特定 的交易品种或者标的,需要将type设置为对应的交易品种类别,将ref设置为对应 的交易品种或者标的

python 复制代码
import jqdata
def initialize(context):
 # 股票类每笔交易时的⼿续费是:买⼊时佣⾦万分之三,卖出时佣⾦万分之三加千分之⼀印花
税, 每笔交易佣⾦最低扣5块钱
 set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=
0.0003, close_commission=0.0003, close_today_commission=0, min_commission=5
), type='stock')

Context 策略信息总览,包含账户、时间等信息

  • subportfolios: 当前单个操作仓位的资⾦、标的信息,是⼀个SubPortfolio 的数组

  • portfolio: 账户信息,即subportfolios 的汇总信息, Portfolio对象,单个操作仓位时,portfolio 指向 subportfolios[0]

  • current_dt: 当前单位时间的开始时间, [datetime.datetime]对象

  • previous_date: 前⼀个交易⽇, [datetime.date]对象, 注意, 这是⼀个⽇期, 是 date, ⽽不是 datetime

  • run_params: 表示此次运⾏的参数, 有如下属性

  1. start_date: 回测/模拟开始⽇期, [datetime.date]对象
  2. end_date: 回测/模拟结束⽇期, [datetime.date]对象
  3. type: 运⾏⽅式, 如下四个字符串之⼀
  4. 'simple_backtest': 回测, 通过点击'编译运⾏'运⾏
  5. 'full_backtest': 回测, 通过点击'运⾏回测'运⾏
  6. 'sim_trade': 模拟交易
  7. 'live_trade': 实盘交易
  8. frequency: 运⾏频率, 如下三个字符串之⼀

'day'

'minute'

'tick'

  • 为了让从其他平台迁移过来的同学更顺⼿的使⽤系统, 我们对此对象也做了和 [g] ⼀样的处理:
  1. 可以添加⾃⼰的变量, 每次进程关闭时持久保存, 进程重启时恢复.
  2. 以 '__' 开头的变量不会被持久保存
  3. 如果添加的变量与系统的冲突, 将覆盖掉系统变量, 如果想恢复系统变量, 请删除⾃⼰的变量.

KD函数

在因⼦库------ 超买超卖型⾥

python 复制代码
KD(security_list, check_date, N = 9, M1 = 3, M2 = 3, unit = '1d', include_n
ow = True, fq_ref_date = None)

参数:

  • security_list:股票列表
  • check_date:要查询数据的⽇期
  • N:统计的天数 N,计算RSV的参数
  • M1:统计的天数 M1,计算K的M1⽇移动平均值
  • M2:统计的天数 M2,计算D的M1⽇移动平均值
  • unit:统计周期,默认为 '1d', ⽀持如下周期: '1m', '5m', '15m', '30m', '60m',
  • '120m', '1d', '1w', '1M'. '1w' 表示⼀周, '1M' 表示⼀⽉
  • include_now:是否包含当前周期,默认为 True
  • fq_ref_date:复权基准⽇,默认为 None

返回:

  • K和D 的值。

返回结果类型:

  • 字典(dict):键(key)为股票代码,值(value)为数据。

  • 如:({'000001.XSHE': 76.634909558440839, '603177.XSHG': nan, '000002.XSHE':31.205826728484286, '601211.XSHG': 65.666306018342183}, {'000001.XSHE': 77.290976650878633, '603177.XSHG': nan, '000002.XSHE': 32.552242430383409,'601211.XSHG': 64.593395785918702})
    ⽤法注释:

  • KD的计算公式与SKDJ的不太⼤,⽽常⻅的炒股软件中均没有找到KD的⽤法注释,所以该处的⽤法注释使⽤的是公式SKDJ的;

  • 指标>80 时,回档机率⼤;指标<20 时,反弹机率⼤;

  • K在20左右向上交叉D时,视为买进信号;

  • K在80左右向下交叉D时,视为卖出信号;

  • SKDJ波动于50左右的任何讯号,其作⽤不⼤。

order_value 按价值下单

python 复制代码
order_value(security, value, style=None, side='long', pindex=0, close_today
=False)
买卖价值为value的标的。

参数:

  • security: 股票名字
  • value: 股票价值,value = 最新价 * ⼿数 * 保证⾦率(股票为1) * 乘数(股
  • 票为100)
  • style: 参⻅OrderStyle, None代表MarketOrder
  • side: 'long'/'short',操作多单还是空单。默认为多单。默认为多单,股票、基 ⾦暂不⽀持开空单。 pindex: 在使⽤set_subportfolios创建了多个仓位时,指定subportfolio 的序号, 从 0 开始, ⽐如 0为 指定第⼀个 subportfolio, 1 为指定第⼆个subportfolio,默认为0。
  • close_today: 平今字段,close_today: 平今字段,仅对上海国际能源中⼼,上海期货交易所,中⾦所⽣效,其他交易所将返回 Order对象或者None, 如果创建委托成功, 则返回Order对象, 失败则返回None
    Position 持仓标的信息
    持有的某个标的的信息,注意区分多仓和空仓
  • security: 标的代码
  • price: 最新⾏情价格
  • acc_avg_cost 是累计的持仓成本,在清仓/减仓时也会更新,该持仓累积的收 益都会⽤于计算成本(⼀开始acc_avg_cost为0,amount也为0),加仓: new_acc_avg_cost = (acc_avg_cost * amount + trade_value + commission) / (amount + trade_amount);减仓:new_acc_avg_cost = (acc_avg_cost * amount - trade_value + commission) / (amount - trade_amount) 说明:commission是本次买⼊或者卖出的⼿续费 avg_cost 是当前持仓成本,
  • hold_cost: 当⽇持仓成本,计算⽅法:当⽇⽆收益:hold_cost = 前收价 (清算后)
  • init_time: 建仓时间,格式为 datetime.datetime
  • transact_time: 最后交易时间,格式为 datetime.datetime
  • locked_amount: 挂单冻结仓位
  • total_amount: 总仓位, 但不包括挂单冻结仓位( 如果要获取当前持仓的仓位,需 要将locked_amount和total_amount相加)
  • closeable_amount: 可卖出的仓位
  • today_amount: 今天开的仓位
  • value: 标的价值,计算⽅法是: price * total_amount * multiplier, 其中股票、
  • 基⾦的multiplier为1,期货为相应的合约乘数
  • side: 多/空,'long' or 'short'
  • pindex: 仓位索引,subportfolio index
    order_target 期货⽬标⼿数下单
python 复制代码
order_target(security, amount, style=None, side='long', pindex=0, close_today=False)
买卖标的, 使最终标的的数量达到指定的amount

参数:

  • security: 标的代码
  • amount: 期望的最终数量
  • style: 参⻅OrderStyle, None代表MarketOrder
  • side: 'long'/'short',操作多单还是空单,默认为多单。
  • pindex: 在使⽤set_subportfolios创建了多个仓位时,指定subportfolio 的序 号, 从 0 开始, ⽐如 0为 指定第⼀个 subportfolio, 1 为指定第⼆个
  • subportfolio,默认为0。
  • close_today: 平今字段返回 Order对象或者None, 如果创建委托成功, 则返回Order对象, 失败则返回None

3 获取KD

python 复制代码
from jqlib.technical_analysis import *
# 定义股票池列表
security_list1 = '000001.XSHE'
security_list2 = ['000001.XSHE','000002.XSHE','601211.XSHG']
# 计算并输出 security_list1 的 KD值
K1, D1 = KD(security_list1, check_date = '2017-01-04', N = 9, M1 = 3, M2 =3)
print('股票1的K1',K1[security_list1]) # K1是⼀个字典
print('股票1的D1',D1[security_list1])
# 输出 security_list2 的 KD 值
K2, D2 = KD(security_list2, check_date = '2017-01-04', N = 9, M1 = 3, M2 =3)
for stock in security_list2:
 print('股票池2的K2',K2[stock])
 print('股票池2的D2',D2[stock])

4 获取KDJ

python 复制代码
from jqlib.technical_analysis import *
security = '000001.XSHE'
check_dates=['2022-09-05','2022-09-06','2022-09-07']
for check_date in check_dates:
 _K,_D,_J = KDJ(security, check_date=check_date, N=9,M1=3,M2=3)
 print(check_date,'K值为:',_K[security])
 print(check_date,'D值为:',_D[security])
 print(check_date,'J值为:',_J[security])

代码

python 复制代码
# 有仓位就卖,没有就买
def initialize(context):
    # 设定一个基准 
    set_benchmark('000300.XSHG')
    g.security = '000001.XSHE'
    # 每日执行
    run_daily(market_open, time='9:30')
    
def market_open(context):
    # 如果没有持仓
    if g.security not in context.portfolio.positions:
        order_target(g.security,100) # 买100股
    else:
        order_target(g.security, 0)  # 全部卖出 

运行回测

双均线策略

python 复制代码
 # 双均线策略 
# 金叉:快线上穿慢线 买 
# 死叉:快线下穿慢线  卖 

def initialize(context):
    g.security = '000333.XSHE'
    g.short_count = 15 # 快线15日
    g.long_count = 30 # 慢线30日 
    g.unit = '1d'
    run_daily(market_open, time='every_bar') 
    
# 获取均线价格
def get_ma(security,count, unit):
    df = attribute_history(security, count+1, unit, ['close'])
    # 计算当前的ma
    now_ma = df[:count+1]['close'].rolling(count).mean()[-1]
    # 前一天的ma
    pre_ma = df[:count]['close'].rolling(count).mean()[-1]
    return [pre_ma,now_ma]
        

# 要执行的策略函数  
def market_open(context):
    # 金叉:快线上穿慢线 买 
    # 15日均线
    short_ma = get_ma(g.security,g.short_count,g.unit)
    # 30日均线
    long_ma = get_ma(g.security,g.long_count,g.unit)
    # 死叉:快线下穿慢线  卖 
    if (long_ma[0]>short_ma[0] and (long_ma[1]<=short_ma[1])):
        print(f'金叉买入,MA{g.short_count}={short_ma},MA(g.long_count)={long_ma}')
        order_target(g.security, 100)
    elif (long_ma[0]<short_ma[0] and (long_ma[1]>short_ma[1])):
        print(f'死叉卖出,MA{g.short_count}={short_ma},MA(g.long_count)={long_ma}')
        order_target(g.security, 0)
        

运行结果

相关推荐
数据智能老司机1 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
武子康2 小时前
大数据-100 Spark DStream 转换操作全面总结:map、reduceByKey 到 transform 的实战案例
大数据·后端·spark
数据智能老司机2 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机3 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机3 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
c8i3 小时前
drf初步梳理
python·django
每日AI新事件3 小时前
python的异步函数
python
expect7g3 小时前
Flink KeySelector
大数据·后端·flink
这里有鱼汤4 小时前
miniQMT下载历史行情数据太慢怎么办?一招提速10倍!
前端·python
databook13 小时前
Manim实现脉冲闪烁特效
后端·python·动效