量化: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)
        

运行结果

相关推荐
Elastic 中国社区官方博客几秒前
如何将数据从 AWS S3 导入到 Elastic Cloud - 第 3 部分:Elastic S3 连接器
大数据·elasticsearch·搜索引擎·云计算·全文检索·可用性测试·aws
q5673152326 分钟前
在 Bash 中获取 Python 模块变量列
开发语言·python·bash
是萝卜干呀26 分钟前
Backend - Python 爬取网页数据并保存在Excel文件中
python·excel·table·xlwt·爬取网页数据
代码欢乐豆27 分钟前
数据采集之selenium模拟登录
python·selenium·测试工具
Aloudata1 小时前
从Apache Atlas到Aloudata BIG,数据血缘解析有何改变?
大数据·apache·数据血缘·主动元数据·数据链路
狂奔solar1 小时前
yelp数据集上识别潜在的热门商家
开发语言·python
Tassel_YUE1 小时前
网络自动化04:python实现ACL匹配信息(主机与主机信息)
网络·python·自动化
水豚AI课代表1 小时前
分析报告、调研报告、工作方案等的提示词
大数据·人工智能·学习·chatgpt·aigc
聪明的墨菲特i1 小时前
Python爬虫学习
爬虫·python·学习
努力的家伙是不讨厌的2 小时前
解析json导出csv或者直接入库
开发语言·python·json