B站热榜视频,炒股源码来了!

本文介绍了量化交易策略——ETF动量轮动,该策略基于股票年化收益和判定系数打分,选择评分最高的ETF进行投资。作者分享了一个在聚宽平台上实现的8年回测收益715.44%的策略代码,并强调了策略的风险和本地化数据API的使用。此外,还提到了Python编程基础和聚宽平台的使用,以及未来可能的实盘交易提醒服务。
摘要由CSDN通过智能技术生成


公众号后台回复“图书“,了解更多号主新书内容
     作者:Jack Cui
     来源:Jack Cui

视频中,承诺的量化交易教程,它来了!

这期视频播放近 70 多万,后来经过 B 站编辑老师的建议,我对视频的部分内容进行了删减。

视频中,我提到,后续我会晒实仓情况,这个行为存在政策风险。

其实,很多好心读者也都提醒过我,这样不妥,很容易造成粉丝跟盘。

所以,后面我就不公布自己的实仓情况了,我们只探讨量化交易技术本身。

希望各位理解。

同时,我自己改进的量化交易算法,里面有一些激进的选股策略,会在我人为圈定的 top20 的股池中,投票选择得分高的几只股票进行买卖。

这个也存在一个问题:

假如这篇文章,一万人阅读,10% 的人,也就是 1000 人跑了这个算法,并真投了一万元。

这也会造成极端情况下,同一时刻,一起交易一千万的情况。这样也是不好的。

所以,今天要说的这个量化交易算法,是我之前测试过的一个基础版策略,也是别人开源过的。

原理都弄懂,你也可以自己改进策略

这个量化交易策略,8 年回测,收益 715.44%,最大回撤 28%。

OK,进入我们今天的正题,量化交易。

聚宽

我目前使用的是聚宽平台,这里也就以它为例进行讲解。

https://www.joinquant.com/

PS:有聚宽工作的朋友吗?广告费记得结一下。

聚宽是一个量化交易平台,在这个平台有很多开源的量化交易策略,社区不错。

同时,使用这个平台,还可以回测我们实现的策略。

左边写好代码,选择时间和金额,就可以使用历史数据进行回测。

因为涉及到编写代码,所以你必须具备 Python 编程基础

没有 Python 基础的小伙伴,先看我的 Python 入门视频吧:

https://www.bilibili.com/video/BV1Sh411a76E/

一定要先好好学 Python,无论你是不是程序员,都很有用。

属于,好学又实用的编程语言。

聚宽平台,有两个 api,可以使用。

一个是在聚宽平台使用的 api:

https://www.joinquant.com/help/api/help#api:API%E6%96%87%E6%A1%A3

如果你是在网页,进行回测,那就需要使用这个 api。

另一个,就是本地化数据 JQData:

https://www.joinquant.com/help/api/help#JQData:JQData

这个 api 是我平时使用的本地化服务接口,只需要 pip 安装一下,就可以本地环境调用接口,获取数据了。

如果你有 Python 基础,那我想这两份 api 使用起来,应该很简单。

ETF 动量轮动

今天要讲的这个量化交易策略,就是在聚宽社区,其他人开源的量化交易算法,起了个名字,叫 ETF 动量轮动。

其实,就是一种长期定投 ETF 的策略,定投大法好。

策略核心有两块,选哪个 ETF,以及何时买卖。

我将这个策略进行了重构,用本地化数据 JQData 的 api 进行了重写。

我对每一行代码,都进行了详细的注释,并罗列了每个知识点,可以参考的文章。

直接看代码吧!

#-*- codig:utf-8 -*-
import jqdatasdk as jq
from datetime import datetime, timedelta
import time
import numpy as np
import math

# https://www.joinquant.com/help/api/help#api:API%E6%96%87%E6%A1%A3
# https://www.joinquant.com/help/api/help#JQData:JQData

# aa 为你自己的帐号, bb 为你自己的密码
jq.auth('aa','bb')

# http://fund.eastmoney.com/ETFN_jzzzl.html
stock_pool = [
    '159915.XSHE', # 易方达创业板ETF
    '510300.XSHG', # 华泰柏瑞沪深300ETF
    '510500.XSHG', # 南方中证500ETF
]

# 动量轮动参数
stock_num = 1           # 买入评分最高的前 stock_num 只股票
momentum_day = 29       # 最新动量参考最近 momentum_day 的

ref_stock = '000300.XSHG' #用 ref_stock 做择时计算的基础数据
N = 18 # 计算最新斜率 slope,拟合度 r2 参考最近 N 天
M = 600 # 计算最新标准分 zscore,rsrs_score 参考最近 M 天
score_threshold = 0.7 # rsrs 标准分指标阈值
# ma 择时参数
mean_day = 20 # 计算结束 ma 收盘价,参考最近 mean_day
mean_diff_day = 3 # 计算初始 ma 收盘价,参考(mean_day + mean_diff_day)天前,窗口为 mean_diff_day 的一段时间

day = 1

# 1-1 选股模块-动量因子轮动 
# 基于股票年化收益和判定系数打分,并按照分数从大到小排名
def get_rank(stock_pool):
    score_list = []
    for stock in stock_pool:
        current_dt = time.strftime("%Y-%m-%d", time.localtime())
        current_dt = datetime.strptime(current_dt, '%Y-%m-%d')
        previous_date  = current_dt - timedelta(days = day)
        data = jq.get_price(stock, end_date = previous_date, count = momentum_day, frequency='daily', fields=['close'])
        # 收盘价
        y = data['log'] = np.log(data.close)
        # 分析的数据个数(天)
        x = data['num'] = np.arange(data.log.size)
        # 拟合 1 次多项式
        # y = kx + b, slope 为斜率 k,intercept 为截距 b
        slope, intercept = np.polyfit(x, y, 1)
        # (e ^ slope) ^ 250 - 1
        annualized_returns = math.pow(math.exp(slope), 250) - 1
        r_squared = 1 - (sum((y - (slope * x + intercept))**2) / ((len(y) - 1) * np.var(y, ddof=1)))
        score = annualized_returns * r_squared
        score_list.append(score)
    stock_dict = dict(zip(stock_pool, score_list))
    sort_list = sorted(stock_dict.items(), key = lambda item:item[1], reverse = True)
    print("#" * 30 + "候选" + "#" * 30)
    for stock in sort_list:
        stock_code = stock[0]
        stock_score = stock[1]
        security_info = jq.get_security_info(stock_code)
        stock_name = security_info.display_name
        print('{}({}):{}'.format(stock_name, stock_code, stock_score))
    print('#' * 64)
    code_list = []
    for i in range((len(stock_pool))):
        code_list.append(sort_list[i][0])
    rank_stock = code_list[0:stock_num]
    return rank_stock

# 2-1 择时模块-计算线性回归统计值
# 对输入的自变量每日最低价 x(series) 和因变量每日最高价 y(series) 建立 OLS 回归模型,返回元组(截距,斜率,拟合度)
# R2 统计学线性回归决定系数,也叫判定系数,拟合优度。
# R2 范围 0 ~ 1,拟合优度越大,自变量对因变量的解释程度越高,越接近 1 越好。
# 公式说明:https://blog.csdn.net/snowdroptulip/article/details/79022532
#           https://www.cnblogs.com/aviator999/p/10049646.html
def get_ols(x, y):
    slope, intercept = np.polyfit(x, y, 1)
    r2 = 1 - (sum((y - (slope * x + intercept))**2) / ((len(y) - 1) * np.var(y, ddof=1)))
    return (intercept, slope, r2)

# 2-2 择时模块-设定初始斜率序列
# 通过前 M 日最高最低价的线性回归计算初始的斜率,返回斜率的列表
def initial_slope_series():
    current_dt = time.strftime("%Y-%m-%d", time.localtime())
    current_dt = datetime.strptime(current_dt, '%Y-%m-%d')
    previous_date  = current_dt - timedelta(days = day)
    data = jq.get_price(ref_stock, end_date = previous_date, count = N + M, frequency='daily', fields=['high', 'low'])
    return [get_ols(data.low[i:i+N], data.high[i:i+N])[1] for i in range(M)]

# 2-3 择时模块-计算标准分
# 通过斜率列表计算并返回截至回测结束日的最新标准分
def get_zscore(slope_series):
    mean = np.mean(slope_series)
    std = np.std(slope_series)
    return (slope_series[-1] - mean) / std

# 2-4 择时模块-计算综合信号
# 1.获得 rsrs 与 MA 信号,rsrs 信号算法参考优化说明,MA 信号为一段时间两个端点的 MA 数值比较大小
# 2.信号同时为 True 时返回买入信号,同为 False 时返回卖出信号,其余情况返回持仓不变信号
# 解释:
#       MA 信号:MA 指标是英文(Moving average)的简写,叫移动平均线指标。
#       RSRS 择时信号:
#               https://www.joinquant.com/view/community/detail/32b60d05f16c7d719d7fb836687504d6?type=1
def get_timing_signal(stock):
    # 计算 MA 信号
    current_dt = time.strftime("%Y-%m-%d", time.localtime())
    current_dt = datetime.strptime(current_dt, '%Y-%m-%d')
    previous_date  = current_dt - timedelta(days = day)    
    close_data = jq.get_price(ref_stock, end_date = previous_date, count = mean_day + mean_diff_day,  frequency = 'daily',  fields = ['close'])
    # 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1,23 天,要后 20 天
    today_MA = close_data.close[mean_diff_day:].mean() 
    # 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0,23 天,要前 20 天
    before_MA = close_data.close[:-mean_diff_day].mean()
    # 计算 rsrs 信号
    high_low_data = jq.get_price(ref_stock, end_date = previous_date, count = N,  frequency='daily',   fields = ['high', 'low'])
    intercept, slope, r2 = get_ols(high_low_data.low, high_low_data.high)
    slope_series.append(slope)

    rsrs_score = get_zscore(slope_series[-M:]) * r2
    # 综合判断所有信号
    if rsrs_score > score_threshold and today_MA > before_MA:
        return "BUY"
    elif rsrs_score < -score_threshold and today_MA < before_MA:
        return "SELL"
    else:
        return "KEEP"

slope_series = initial_slope_series()[:-1] # 除去回测第一天的 slope ,避免运行时重复加入

def get_test():
    for each_day in range(1, 100)[::-1]:
        current_dt = time.strftime("%Y-%m-%d", time.localtime())
        current_dt = datetime.strptime(current_dt, '%Y-%m-%d')
        previous_date  = current_dt - timedelta(days = each_day - 1)
        day = each_day
        print(each_day, previous_date)
        check_out_list = get_rank(stock_pool)
        for each_check_out in check_out_list:
            security_info = jq.get_security_info(each_check_out)
            stock_name = security_info.display_name
            stock_code = each_check_out
            print('今日自选股:{}({})'.format(stock_name, stock_code))
        #获取综合择时信号
        timing_signal = get_timing_signal(ref_stock)
        print('今日择时信号:{}'.format(timing_signal))
        print('*' * 100)

if __name__ == "__main__":
    check_out_list = get_rank(stock_pool)
    for each_check_out in check_out_list:
        security_info = jq.get_security_info(each_check_out)
        stock_name = security_info.display_name
        stock_code = each_check_out
        print('今日自选股:{}({})'.format(stock_name, stock_code))
    #获取综合择时信号
    timing_signal = get_timing_signal(ref_stock)
    print('今日择时信号:{}'.format(timing_signal))
    print('*' * 100)

策略很短,不到 200 行。

需要注意的是,这个本地化的 api,需要通过官网申请后,才能使用。

申请地址:

https://www.joinquant.com/default/index/sdk

对应的,可以直接在聚宽平台运行的代码,在这里:

https://github.com/Jack-Cherish/quantitative/blob/main/lesson1/quantitive-etf-jq.py

输入代码,就可以直接运行,回测效果了。

时间有限,这里先写这么多。

这个策略,只用了宽基,轮动选择

后续我会继续讲解,怎样将这个策略部署到我们的服务器上,并定时给我们的手机发送邮件,进行交易提醒。

股市有风险,入市需谨慎,请谨慎使用~

有什么问题,欢迎在评论区里留言。

◆ ◆ ◆  ◆ ◆
麟哥新书已经在当当上架了,我写了本书:《拿下Offer-数据分析师求职面试指南》,目前当当正在举行活动,大家可以用相当于原价5折的预购价格购买,还是非常划算的:


数据森麟公众号的交流群已经建立,许多小伙伴已经加入其中,感谢大家的支持。大家可以在群里交流关于数据分析&数据挖掘的相关内容,还没有加入的小伙伴可以扫描下方管理员二维码,进群前一定要关注公众号奥,关注后让管理员帮忙拉进群,期待大家的加入。
管理员二维码:
猜你喜欢
● 卧槽!原来爬取B站弹幕这么简单● 厉害了!麟哥新书登顶京东销量排行榜!● 笑死人不偿命的知乎沙雕问题排行榜
● 用Python扒出B站那些“惊为天人”的阿婆主!● 你相信逛B站也能学编程吗
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
★★1.编译注意事项 使用VC6打开工作区StkUI.dsw 然后可以按照以下顺序依次编译各个工程 GuiLib、profuisdll、XPFace、StkLib、StkNet、StkUI、Tools 其中工程StkUI是软件的主界面程序,Tools 是注册机以及一些简单的工具,其他 都是动态连接库。 ★★2.工程profuisdll介绍 profuisdll是一套比较专业的Windows界面库,是俄国人做的,还不错,本软件 改正了它的几个bug。在ProfUIS\Modified.txt文件中有说明。 本软件3.0版仅使用了该界面库的颜色选择对话框。 ★★3.工程GuiLib介绍 GuiLib是另一套Windows界面库,本软件改正了它的几个bug。在GuiLib\Modified.txt 文件中有说明。 本软件3.0版使用了该界面库的界面框架、菜单条、工具条。 ★★4.工程XPFace介绍 主要是本软件的一些界面美化的类,放在了这个DLL里面。 ★★5.工程StkLib介绍 这个工程是实现股票数据结构、技术指标计算的动态连接库,代码与平台无关。 其中比较重要的几个文件如下: Database.h 读取数据文件接口定义 QianLong.h 钱龙格式数据文件接口定义 SelfDB.h 自有格式数据文件接口定义,除了除权数据和行情数据外, 其他与钱龙一样 Stock.h 股票数据结构定义 Technique.h 技术指标类定义 Container.h 股票信息数据CStockInfo的数组类 Express.h 股票列表视图的列变量定义,以及自定义列的表达式计算 Strategy.h 策略定义 Profile.h 记录软件的用户配置并保存 BaseData.cpp 基本资料数据结构类实现 Database.cpp 数据文件读写实现 DRData.cpp 除权数据结构数组类实现 KData.cpp K线数据结构数组类实现 Report.cpp 行情数据结构数组类实现 Minute.cpp 行情分时数据结构数组类实现 Outline.cpp 行情额外数据结构数组类实现 QianLong.cpp 钱龙数据文件读写实现 SelfDB.cpp 自有格式数据文件读写实现 Stock.cpp 股票数据结构实现 StStore.cpp 数据文件读写实现 TechCL.cpp 自有技术指标 TechEnergy.cpp 能量类技术指标 TechKLine.cpp K线叠加类技术指标 Technique.cpp 技术指标基类 TechSwing.cpp 摆动类技术指标 TechTrend.cpp 趋势类技术指标 TechOther.cpp 其它类技术指标 Container.cpp 股票信息数据CStockInfo的数组类实现 Express.cpp 股票列表视图的列变量定义,以及自定义列的表达式计算实现 Strategy.cpp 策略定义实现 Profile.cpp 记录软件的用户配置并保存 有关详细的说明,参看源文件中的注释。 工程StkLib的几个全局静态变量: g_stockcontainer:AfxGetStockContainer()可以得到该变量的引用,该 变量记录所有股票的行情信息和基本信息,CStockInfo的数组。 g_domaincontainer:AfxGetDomainContainer()可以得到该变量的引用, 该变量记录所有板块的信息。 g_groupcontainer:AfxGetGroupContainer()可以得到该变量的引用,该 变量记录所有分组的信息。 g_stdatabase:AfxGetDB()可以得到该变量的引用,该变量实现了本软件的 数据文件接口。 g_stprofile:AfxGetProfile()可以得到该变量的引用,该变量记录当前软 件的一些设置。 ★★6.工程StkNet介绍 这个工程是实现网络数据自动下载功能的动态连接库。其中比较重要的几个文 件如下: NetDB.h 一些数据下载,安装的接口 HttpClt.h HTTP协议客户端类 InfoZip.h 压缩/解压缩Zip文件 Markup.h XML解析 XMLDoc.h XML辅助 secret.h 主要包括一些注册机的加密算法和读取硬盘序列号的类。 NetDB.cpp 一些数据下载,安装的接口实现 HttpClt.cpp HTTP协议客户端类实现 InfoZip.cpp 压缩/解压缩 Markup.cpp XML解析实现 Secret.cpp 加密文件,读取硬盘系列号等 XMLDoc.cpp XML辅助实现 secret.cpp 主要包括一些注册机的加密算法和读取硬盘序列号的类实现。 其中工程中的Tongshi Files为支持通视卡行情的实现程序 其中工程中的Yongxin Files为支持清华永新卡行情的实现程序 其中工程中的Receiver Files为本软件的行情接收的实现程序,其中将通视卡和清 华永新卡的数据结构转换成本软件内的通用数据结构,报价(REPORT)、分时(MINUTE)、 额外(OUTLINE)、K线(KDATA)、除权信息(DRDATA) 工程StkNet的全局静态变量: g_sview:AfxGetSView()可以得到该变量的引用,该变量记录注册信息。 ★★7.工程StkUI介绍 该工程生成最终可执行文件,主要是软件的界面。主要几个文件如下: BaseView.cpp 基本资料视图 ChildFrm.cpp 子窗口框架 MainFrm.cpp 主框架,响应菜单命令 StkUI.cpp 应用程序类,主程序初始化,初始数据读取等 StaticDoc.cpp 文档类 WizardView.cpp 向导视图 SimuView.cpp 策略视图 MarketView.cpp 实时行情视图 SListView.cpp 股票列表视图 StockGraph.cpp 技术指标视图画图类 DrawTech.cpp 画具体技术指标的函数,属于CGraphView类的方法 GraphView.cpp 技术指标视图 StrategyView.cpp 策略树视图 GroupView.cpp 股票分组树视图 TechsView.cpp 技术指标树视图 ★★8.工程Tools介绍 该工程包含以下几个模块: 注册机,利用了StkNet工程导出的AfxGetSView()。 从txt基本资料文件中提取财务数据的小工具。 修改文件时间的小工具。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值