set_option() 设置参数

3.5万
0
2023-09-17 17:12:11
3
投币
收藏
1
主要发布:数学思维与文化、少儿编程、发明创造、《新概念英语》背诵相关视频
3559.1万播放
简介
var 样本值的方差
00:05
df.var() 拷贝代码
00:08
data= 数据
00:05
强制连接允许重复
00:18
df.var() 进入研究环境
00:09
按列计算数据的方差值
00:11
df.std()
00:10
std 样本值的标准差
00:06
df.std() 拷贝代码
00:10
df.std() 得到运行结果
00:17
df.skew()
00:09
skew 样本值得偏度(三阶矩)
00:07
df.skew() 无参数直接运行
00:06
df.skew() 拷贝代码
00:10
df.skew() 获得各列的计算结果
00:18
df.skew() 偏度数据
00:10
偏度 来度量概率分布的不对称性
00:08
取值范围在负无穷和正无穷之间
00:08
偏度小于零,概率分布左偏
00:08
偏度大于零,概率分布右偏
00:10
偏度为零,表示相对均匀的分布在两侧。但不是绝对均匀
00:16
样本值的三阶矩
00:14
df.kurt()
00:05
kurt 样本值得峰度
00:07
kurt 样本值得峰度(四阶矩)
00:07
df.kurt() 拷贝代码
00:14
df.kurt() 运行结果显示出来
00:22
随机变量分布的陡峭程度
00:18
峰度的取值在 1 到争取穷之间
00:06
完全正态分布的峰度是 3
00:07
峰度越大,概率分布越高尖
00:09
峰度值越小,概率分布越矮胖
00:12
峰度值减去 3 得到 超值峰度
00:09
此时 0 表示正态分布
00:09
大于 0 则比正态分布更高尖一些
00:07
小于 0 则比正太分布更矮胖
00:07
OHLC 数据峰度值分析
00:24
计算是 OHLC 数据,他们的峰度值也有很大差别
00:10
df.cumsum()
00:12
cumsum 样本值得累计和
00:07
累计和的解释
00:20
df.cumsum() 每一行都是之前所有行的累加和
00:19
df.cummin()
00:09
cummin,cummax 样本值的累计最大值和累计最小值
00:10
打开研究环境
01:01
df.cummin() 拷贝代码
00:15
df.cummin() 运行成功
00:33
print(df) 输出数据框
00:18
df.cummin() 结果分析
00:59
cummax() 进行分析
00:09
df.cummax() 拷贝代码
00:14
df.cummax() 运行成功
00:13
df.cumprod()
00:07
cumprod 样本值得累计积
00:06
df.cumprod() 拷贝代码
00:14
结果越来越大。累计乘积
00:17
df.diff()
00:07
diff 计算一阶差分
00:06
diff 计算一阶差分 的定义
00:12
df.diff() 拷贝代码
00:13
df.diff() 运行结果正确
00:13
df.diff() 结果分析
00:43
df.pct_change()
00:08
pct_change 计算百分数变化
00:07
df.pct_change() 拷贝代码
00:08
df.pct_change() 计算结果正确
00:11
df.pct_change() 结算结果分析
00:44
dataframe】常用统计函数
00:13
panel类型数据分解成dataframe
00:23
panel类型数据分解成dataframe 包含两个部分
00:11
panel类型数据分解成dataframe方法
00:06
更多panel操作指路
00:07
panel类型数据怎么处理
00:17
获得一个panel类型数据作为样例
00:06
pa=get_price()
00:10
['000001.XSHE','000002.XSHE','000004.XSHE']
00:15
start_date='2016-02-01'
00:08
end_date='2016-02-04'
00:08
fields=['open','high','low','close']
00:07
pa 输出运行结果
00:17
生成新的代码框
00:28
panel 数据获取代码拷贝
00:17
运行代码获取 panel 数据成功
00:17
不建议继续使用panel
00:12
似乎是 Python 2.7 版本中出现
00:15
class 'pandas.core.panel.Panel'
00:10
Dimensions 4 (items) x 4 (major_axis) x 3 (minor_axis)
00:08
Items axis close to open
00:09
Major_axis axis
00:13
Minor_axis axis
00:10
dataframe是一个二维的表,panel则是三维的“包”
00:21
panel 数据不再被支持。不进行深入介绍
00:20
研究内存取dataframe
00:14
内存取dataframe - 什么是内村取
00:29
把dataframe存成csv文件
00:09
csv文件。逗号分隔符
00:06
df.to_csv()
00:06
读取被存成csv文件的dataframe
00:07
pd.read_csv()
00:05
【dataframe】研究内存取
00:11
import pandas as pd
00:08
获取一个dataframe类型的数据为例
00:06
df=get_price()
00:09
'000001.XSHE'
00:08
start_date='2016-02-01',end_date='2016-02-04'
00:07
frequency='daily'
00:06
fields=['open','high','low','close']
00:07
df 输出 数据框
00:05
拷贝代码生成新的代码框
00:16
粘贴代码到代码框中准备运行
00:09
运行代码获得 OHLC 数据
00:17
# 获取一个 dataframe 类型的数据为例
00:16
df.to_csv() 存为 csv 文件
00:09
用法如下,文件都是存到研究空间中的
00:12
如果不写路径是默认是存在根目录
00:06
如df.to_csv('df.csv')
00:09
把dataframe存成csv文件,保存到研究school文件夹中命名为df.csv
00:14
df.to_csv('school 斜杠 df.csv')
00:06
df.to_csv('school 斜杠 df.csv') 拷贝代码
00:11
没有直接得到反馈信息
00:14
读取被存成csv文件的dataframe
00:13
pd.read_csv()
00:06
读取研究中school文件夹中命名为df.csv为df2
00:12
df2=pd.read_csv('school df.csv',index_col=[0])
00:07
df2=pd.read_csv('school df.csv',index_col=[0]) 拷贝代码
00:15
name 'pd' is not defined
00:15
import pandas as pd 导入 pandas 库再看
00:19
无异常信息,应该是读取文件成功
00:11
df2 输出数据框的数据
00:09
写入读取文件成功
00:24
pandas.dataframe 专题使用指南 - 每个网页都认真讲了一遍
00:12
量化交易零基础入门教程
00:34
综合之前所学写一个策略
00:19
灵感细化
00:08
逐步实现策略
00:04
调整与改进策略
00:05
自测与自学
00:05
通过前文基础知识的学习,本文将引导读者运用所学写成一个策略
00:11
如果发现某些知识忘了很正常
00:11
之前也提到过策略灵感的来源多种多样
00:10
可能是通过阅读、通过与人交流、或是通过自己感悟与研究
00:10
灵感最初可能只是模糊的感觉或疑问
00:08
比如“感觉低市盈率的股票好像长期收益更好”
00:09
“当股价一旦超过整百的时候会不会更容易继续涨一段”
00:13
会不会有模式长期存在
00:07
“这个股票和那个股票的股价数据看起来好像符合某种统计规律”
00:10
验证灵感的一个基本方法是把灵感细化,写成策略做回测
00:11
小市值股票过去很长一段时间内收益特别好,但最近不太行了
00:13
你觉得这件事比较有价值,想要写成策略来回测验证下
00:09
请思考下,应该写一个什么样的策略来验证这件事呢?
00:08
为了验证灵感,我们把灵感细化成内容如下的这样一个策略
00:10
每天找出市值排名最小的前10只股票作为要买入的股票
00:10
若已持有的股票的市值已经不够小而不在要买入的股票中,则卖出这些股票
00:13
买入要买入的股票,买入金额为当前可用资金的10分之一
00:08
考虑到不一定要选10个股票
00:07
股票数量应该是个可以方便调节的变量
00:07
因此策略内容改成如下这样更好
00:06
设定好要交易的股票数量stocksnum
00:06
每天找出市值排名最小的前stocksnum只股票作为要买入的股票
00:10
若已持有的股票的市值已经不够小而不在要买入的股票中, 则卖出这些股票
00:10
买入要买入的股票,买入金额为当前可用资金的stocksnum分之一
00:10
最终目的是要写成代码交给计算机回测
00:23
因此要逐步把文字的意思用代码实现
00:09
首先要把这个策略放到之前讲过的初始化与周期循环的策略框架中
00:13
run_daily(period,time='every_bar')
00:13
def initialize(context)
00:12
run_daily(period,time='every_bar') 代码分析
00:12
设定好要交易的股票数量stocksnum
00:16
def period(context)
00:14
找出市值排名最小的前stocksnum只股票作为要买入的股票
00:11
逐步实现,对于不确定的东西print打印出来看看
00:09
若已持有的股票的市值已经不够小而不在要买入的股票中,则卖出这些股票
00:14
买入要买入的股票,买入金额为可用资金的stocksnum分之一
00:09
接下来,你只需要逐步的把策略的全部内容用代码实现出来
00:12
技巧是把复杂的内容拆分成多个简单的内容
00:09
遇到困难可以看下我下面给出提示,所有提示后面会给出参考代码
00:11
往下读之前,建议自己独立实现下试试
00:09
基本都是用讲过的内容
00:07
代码编写相关提示
00:09
设定好要交易的股票数量stocksnum
00:09
这句非常简单,需要注意的是要用到之前讲过的全局变量
00:09
g. 开头的变量是全局变量
00:11
找出市值排名最小的前stocksnum只股票作为要买入的股票
00:12
首先使用get_all_securities取其index得到股票列表
00:14
然后,使用获取财务数据的方法找出当前全市场股票中市值最小的前stocksnum个的股票代码
00:15
get_all_securities
00:13
获取财务数据的方法
00:17
若已持有的股票的市值已经不够小而不在要买入的股票中,则卖出这些股票
00:15
使用context数据获取当前持仓情况
00:09
context
00:21
用for循环语句与if判断语句判断股票是否在当前持仓中
00:11
用in判断是否一个元素在某list中
00:09
context 中有现有持仓股票列表
00:12
现有持仓不在列表中的可以马上清仓
00:15
用in判断是否在待买入股票列表中
00:19
用下单API实现卖出操作
00:07
下单API 多种交易股票的方式
00:14
买入要买入的股票
00:08
买入金额为可用资金的stocksnum分之一
00:08
使用context数据获取当前可用资金总量
00:08
用for循环与下单API实现买入每个要买入的股票
00:09
参考代码
00:13
def initialize(context)
00:11
run_daily(period,time='every_bar')
00:14
设定好要 交易的 股票数量 stocksnum
00:08
g.stocksnum = 10
00:10
def period(context)
00:11
找出市值排名 最小的前 stocksnum 只股票作为要 买入的股票
00:10
获取当天的股票列表
00:07
scu = get_all_securities(date= context.current_dt).index.tolist()
00:16
get_all_securities() 获取当前股票代码
00:11
date = context.current_dt
00:11
.index 行索引,股票代码
00:27
.tolist() 转换成列表
00:11
选出在scu内的市值排名最小的前stocksnum只股票
00:11
q=query() 获得查询对象
00:11
valuation.code
00:07
filter() 过滤满足条件的股票
00:12
valuation.code.in_(scu)
00:19
order_by() 进行排序的子句
00:10
valuation.market_cap.asc() 市值升序排序
00:12
limit(g.stocksnum)
00:13
limit(g.stocksnum) 选择股票的数量
00:15
查询代码分析
00:40
df = get_fundamentals(q)
00:12
get_fundamentals() 按要求筛选满足条件的股票生成 数据框
00:12
选取股票代码并转为list
00:05
buylist=list(df['code'])
00:06
df['code'] 取出股票代码这一列
00:13
list(df['code'])
00:05
若已持有的股票的市值已经不够小而不在要买入的股票中,则卖出这些股票
00:11
对于每个当下持有的股票进行判断
00:08
现在是否已经不在buylist里,如果是则卖出
00:08
使用 for 循环来遍历分析每只股票
00:08
for stock in context.portfolio.positions
00:12
stock for 循环中的临时变量
00:08
context.portfolio.positions
00:16
for stock in context.portfolio.positions
00:10
if stock not in buylist
00:10
如果stock不在buylist
00:07
if stock not in buylist 条件判断
00:21
order_target(stock, 0)
00:08
调整stock的持仓为0,即卖出
00:07
调整stock的持仓为0,即完全清仓这支股票
00:08
order_target(stock, 0) 代码分析
00:23
买入要买入的股票
00:06
买入金额为可用资金的stocksnum分之一
00:08
将资金分成g.stocksnum份
00:06
可用资金的stocksnum分之一
00:11
先平仓再买入
00:18
先释放资金再买入
00:12
position_per_stk = context.portfolio.cash 除法 g.stocksnum
00:10
position_per_stk 每只股票的仓位
00:09
context.portfolio.cash 除法 g.stocksnum
00:11
context.portfolio.cash g.stocksnum 代码分析
00:18
position_per_stk = context.portfolio.cash g.stocksnum 计算每只股票应该有的额度
00:18
用position_per_stk大小的g.stocksnum份资金去买buylist中的股票
00:13
for stock in buylist
00:15
for stock in buylist 代码分析
00:15
order_value(stock, position_per_stk)
00:07
order_value() 根据股票市值自动计算
00:07
order_value(stock, position_per_stk) 循环操作
00:21
调整与改进
00:08
至此这已经是一个完整可运行的策略了
00:09
你可以试试看
00:17
回测结果应该已经可以一定程度上验证灵感了
00:07
不过虽然策略完成
00:11
我们却发现现在策略是每天进行一次选股并交易
00:09
每天进行一次选股并交易
00:14
我们觉得这太频繁了
00:06
希望能实现通过一个变量period控制操作的周期
00:08
即每period天进行一次选股并交易
00:07
依然建议先试着自己做下
00:14
提示如下,提示之后是参考代码
00:07
像stocksnum那样用全局变量的方式建立period变量
00:08
用一个变量记录策略运行天数
00:07
用取余运算配合if判断语句判断是否又经过period天
00:09
参考代码
00:08
def initialize(context) 改进后
00:08
run_daily(period,time='every_bar')
00:09
run_daily(period,time='every_bar') 代码分析
00:14
设定好要交易的股票数量
00:07
g.stocksnum = 7
00:06
g.stocksnum = 7 赋值为 7
00:10
g.stocksnum = 7 全局变量
00:10
设定交易周期
00:07
设定交易周期 - 代码分析
00:21
g.period = 13
00:05
g.period 代码分析
00:09
记录策略进行天数
00:06
记录策略进行天数 - 控制交易频率
00:15
g.days = 0
00:04
g.days
00:05
def period(context)
00:09
判断策略进行天数是否能被轮动频率整除余1
00:11
if g.days % g.period == 0
00:08
g.days % g.period
00:08
if g.days % g.period == 0 - 代码分析
00:33
if g.days % g.period == 0 满足条件才运行否则直接结束
00:10
找出市值排名最小的前 stocksnum 只股票作为要买入的股票
00:09
获取当天的股票列表
00:07
scu = get_all_securities(date= context.current_dt).index.tolist()
00:07
scu = get_all_securities(
00:09
date= context.current_dt
00:10
get_all_securities(date= context.current_dt)
00:11
.index
00:12
.index - 行索引是股票代码
00:15
.tolist()
00:13
.tolist() 转换成列表
00:15
选出在scu内的市值排名最小的前stocksnum只股票
00:13
q=query() 生成对象
00:08
valuation.code
00:09
valuation.code.in_(scu)
00:16
filter() 只查询列表中的代码
00:08
valuation.market_cap.asc()
00:12
order_by( ) 对股票代码排序的方式
00:09
g.stocksnum 股票数量
00:07
limit(g.stocksnum) 限制数量范围
00:06
q=query(valuation.code) 代码分析
00:28
df = get_fundamentals(q)
00:07
get_fundamentals(q)
00:07
get_fundamentals(q) 查询满足条件的股票
00:09
放大代码方便分析
00:13
若已持有的股票的市值已经不够小而不在要买入的股票中,则卖出这些股票
00:12
对于每个当下持有的股票进行判断
00:07
现在是否已经不在buylist里,如果是则卖出
00:08
for stock in context.portfolio.positions
00:11
stock
00:09
context.portfolio.positions
00:11
for stock in context.portfolio.positions 遍历每一只股票
00:14
if stock not in buylist
00:10
如果stock不在buylist
00:06
if stock not in buylist 代码分析
00:18
order_target(stock, 0)
00:10
调整stock的持仓为0,即卖出
00:06
调整stock的持仓为0。并非简单卖出而是全部清仓
00:07
order_target(stock, 0) 代码分析
00:15
买入金额为可用资金的 stocksnum 分之一
00:06
将资金分成g.stocksnum份
00:07
position_per_stk = context.portfolio.cash 除号 g.stocksnum
00:12
position_per_stk 每只股票的仓位计算
00:15
context.portfolio.cash 现金数量
00:07
context.portfolio.cash 除法 g.stocksnum。每只股票分多少现金
00:10
用position_per_stk大小的g.stocksnum份资金去买buylist中的股票
00:11
用 position_per_stk 大小的g.stocksnum份资金去买 buylist中的股票
00:14
代码有问题。初始交易没有问题
00:19
context.portfolio.cash 股票数量不对
00:26
g.stocksnum 总的股票购买数量
00:16
希望换多少只股票,平均分配资金
00:07
for stock in buylist
00:10
for stock in buylist 针对买入列表中的每只股票做循环
00:10
order_value(stock, position_per_stk)
00:07
order_value() 按照价值计算
00:09
stock, position_per_stk。每只股票的额度做计算
00:08
策略进行天数增加1
00:06
g.days = g.days + 1
00:05
g.days = g.days + 1 在 if 外面,坚决执行
00:23
初始化函数代码复习
00:20
天数是否满足条件,否则不会运行
00:22
选出满足市值最小条件的股票列表
00:33
不在列表中直接清仓,在列表中的就计算头寸并买入
00:19
小市值策略如何进行回测
00:20
看看过去 10-15 年的整体表现
00:23
拷贝代码进入环境
00:25
拷贝下一段,正确的代码
00:28
代码拷贝完成,缩进有错误
00:37
修改初始化函数的缩进
00:21
def period(context) 缩进处理
00:35
q=query(valuation.code 必须缩进处理
00:18
股票交易数量为 10 只
00:12
for stock in buylist 都要缩进处理
00:21
g.days = g.days + 1 不是 if 的一部分。不用缩进
00:24
缩进成功,代码正常运行
00:31
聚宽小市值 - 命名
00:16
2010年开始交易
00:17
结束时间调整到 2023-09-15 昨天收盘
00:14
资金规模调整到 1000 万
00:13
聚宽每天免费运行代码 60 分钟
00:36
每年都有很多基本面事件
00:49
2022-2023 年表现不佳
00:34
最大回撤非常严重
00:47
模型购买了许多 ST 股票
00:20
因为 ST 股票往往已经下跌严重。市值很低
00:13
2022年以来下跌严重风险很大
00:18
只用 2.5 分钟,时间很短,效果很不错
00:11
策略初步写完,把g.period设为13
00:14
g.stocksnum设为7
00:06
初始资金设为100000
00:05
频率为天
00:06
回测起止日期为20150101-20180627
00:08
然后进行回测,回测结果如下
00:07
可见15年到16年该策略表现貌似不错,但随后17年至今则表现平平
00:14
自测与自学
00:06
自己实现下本文策略
00:05
思考g.period,g.stocksnum各自设为多少效果比较好?
00:09
思考此文中,虽然每次都等资金的买入
00:16
为何各股票的持仓价值其实还是不同,而且可能越差越大?
00:08
在本文策略中加入止损或止盈
00:06
试着在本文策略中选股时排除st股票、停牌股票、与涨停股票
00:09
这个问题可能会有些挑战,因为会涉及到简单但没讲过的内容
00:10
比较考察搜素与自学能力,但这是做投资交易最为重要的能力
00:08
打开系统自带的示例策略
00:34
改名字-聚宽示例
00:14
聚宽示例-共73行代码
00:12
2010-1-1 开始交易
00:12
2023-9-15 结束交易
00:10
管理规模是 1000 万人民币
00:07
聚宽示例模型亏损严重
01:52
聚宽示例 模型只交易了一只股票
00:19
模型损失严重都不想介绍了
00:31
改成 100 天看效果
00:18
最终收益率接近 100%,跑过了定期存款
01:54
5.30% 年化收益率
00:07
0.279 胜率不高
00:08
1.843 盈亏比还不错
00:07
修改参数要求高出均价 5% 才进场
00:44
收益率只有 4.8% 比前面更低
01:42
改成 50 日均线出信号
00:27
改成 50 天后收益率又提高了一些
01:15
6.11% 收益率提高了
00:07
比定期存款利率更高了
00:12
胜率较高
00:09
count=30 根据 30 日数据做模型
00:13
均线参数太小很容易触发信号
02:00
0.45% 收益率很低
00:08
收益率 和 盈亏比都比较低
00:08
50日均线 和 3% 触发
00:25
整体表现还不错
01:51
6.33% 复合收益率还好
00:12
0.386 胜率较低,但还好
00:13
参数修改之后可以考虑这个模型了
00:21
固定选股 000001
00:27
ETF 基金尝试
00:18
df = get_all_securities(types='etf')
01:37
print(df) 结构更加混乱
00:14
原始形式结构更完整
00:18
df.head(100)
00:49
百度找到 沪深300 ETF 代码是 510300
00:18
510300.XSHG
00:28
运行出现错误
00:33
收益率不错。大多数时候在指数下方
00:32
一般个股比 ETF 涨的更猛,跌得也更猛
00:12
2012年6月就有沪深300的ETF
00:25
2012年7月1日,开始没问题
00:39
基准是 沪深300 指数
00:40
2018 年维持住了稳定
00:40
ETF 比指数基准收益略高
01:29
改回平安银行代码
00:25
改回起始日期
00:15
开始分析这个示例代码
00:18
导入函数库
00:05
from jqdata import 星
00:07
初始化函数,设定基准等等
00:06
def initialize(context)
00:06
设定沪深300作为基准
00:05
set_benchmark('000300.XSHG')
00:07
'000300.XSHG'
00:09
开启动态复权模式(真实价格)
00:08
真实价格
00:13
set_option('use_real_price', True)
00:12
set_option() 设置参数
00:11
'use_real_price'
00:08
'use_real_price', True
00:11
log.info('初始函数开始运行且全局只运行一次')
00:13
log.info()
00:10
股票相关设定
00:13
股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱
00:22
set_order_cost()
00:08
OrderCost()
00:08
close_tax=0.001
00:16
open_commission=0.0003
00:09
close_commission=0.0003
00:07
min_commission=5
00:08
type='stock'
00:08
运行函数
00:18
(reference_security为运行时间的参考标的
00:16
传入的标的只做种类区分
00:08
因此传入'000300.XSHG'或'510300.XSHG'是一样的
00:14
参考标的指数在回测时经常看到
00:23
开盘前运行
00:15
run_daily() 每日运行
00:08
before_market_open() 开盘前运行
00:22
time='before_open'
00:14
可以直接设置为开盘前的某个时间
00:18
reference_security='000300.XSHG'
00:12
开盘时运行
00:06
run_daily(market_open
00:20
time='open'
00:08
收盘后运行
00:13
run_daily(after_market_close
00:10
time='after_close'
00:07
run_daily( 每日都在运行
00:19
time= 以字符串形式直接设置
00:12
初始化函数总结
00:28
开盘前运行函数
00:09
def before_market_open(context)
00:13
输出运行时间
00:10
log.info()日志中写入开盘运行时间
00:09
日志中写入,函数运行的时间
00:10
'函数运行时间(before_market_open):'
00:16
str(context.current_dt.time())
00:21
log.info( '函数运行时间(before_market_open):' + str(context.current_dt.time()) )
00:18
要操作的股票:平安银行
00:11
g.为全局变量
00:11
g.security = '000001.XSHE'
00:10
'000001.XSHE'
00:19
开盘时运行函数
00:07
def market_open(context)
00:12
log.info('函数运行时间(market_open):'+str(context.current_dt.time()))
00:26
security = g.security
00:14
security = g.security 全局变量,其他函数可以直接使用
00:17
获取股票的收盘价
00:06
get_bars() 读取股价数据
00:23
security 股票代码
00:13
count=50
00:12
unit='1d'
00:07
读取数据必须知道基本单位
00:15
fields=['close']
00:16
['close'] 读取收盘价数据
00:14
get_bars(security, count=50, unit='1d', fields=['close'])
00:08
get_price('000001.XSHE',start_date='2016-02-01',end_date='2016-02-03'
00:16
get_bars(security, count=50
00:14
get_bars() 如何使用。后面详细介绍
00:14
取得过去五天的平均价格
00:08
取得过去50天的平均价格
00:16
close_data['close'].mean()
00:23
MA50 修改变量名
00:52
MA50 = close_data['close'].mean()
00:14
取得上一时间点价格
00:07
close_data['close'][-1]
00:14
current_price = close_data['close'][-1]
00:13
如果上一时间点价格高出50天平均价 3%, 则全仓买入
00:31
条件判断语句
00:21
if (current_price 大于 1.03 星号 MA50) and (cash 大于 0)
00:10
current_price 大于 1.03星号MA50
00:29
(cash 大于 0)
00:08
取得当前的现金
00:08
context.portfolio.available_cash
00:10
cash = context.portfolio.available_cash
00:17
同时满足两个条件可以准备买入股票
00:26
记录这次买入
00:06
有重要操作可以在日志中记录
00:14
log.info('价格高于均价 3%%, 买入 %s' % (security))
00:30
用所有 cash 买入股票
00:07
没有选股,只有择时。满足条件全部买入
00:16
order_value(security, cash)
00:18
order_value(security, cash) 代码分析
00:14
如果上一时间点价格低于50天平均价, 则空仓卖出
00:18
卖出条件判断
00:20
current_price 小于 MA50
00:15
context.portfolio.positions[security].closeable_amount 大于 0
00:14
context.portfolio.positions[security].closeable_amount 大于 0
00:32
91、记录这次卖出
00:09
log.info('价格低于均价, 卖出 %s' % (security))
00:07
卖出所有股票,使这只股票的最终持有量为0
00:11
order_target(security, 0)
00:06
order_target(security, 0) 最终持仓为 0
00:18
收盘后运行函数
00:06
def after_market_close(context)
00:13
log.info(str('函数运行时间(after_market_close):'+str(context.current_dt.time())))
00:08
log.info(str('函数运行时间(after_market_close):'+str(context.current_dt.time()))) 转
00:21
得到当天所有成交记录
00:07
trades = get_trades()
00:13
get_trades()
00:16
for _trade in trades.values()
00:13
for _trade in trades.values() 遍历每条交易记录
00:19
log.info('成交记录:'+str(_trade))
00:22
log.info('一天结束')
00:06
log.info('##############################################################')
00:13
起始时间 2023-01-01
00:19
为什么设置这个起始时间
00:18
结束时间 2023-9-15
00:08
资金额度是 1000 万
00:07
时间周期是每日
00:08
编程语言是 Python 3
00:14
编译运行 方式
00:12
正在加载日志
00:12
成功运行了程序看到结果
00:19
编译运行 没有统计分析,效率更高
00:28
为什么选择沪深300指数作为标的
00:31
打开系统,新建一个策略
00:35
买入要买入的股票
00:07
导入pandas模块,必须导入
00:09
编译运行程序,获取所有日志
00:31
初始函数开始运行且全局只运行一次
00:26
2023-01-03 09 00 00 - INFO - 函数运行时间(before_market_open)
00:26
before_open 对应早上 9 点
00:21
open 对应时间是 9 点半
00:13
2023-01-03 09 30 00 - INFO - 价格高于均价 3%, 买入 000001.XSHE
00:12
之前就有大量交易数据,直接生成交易信号
00:39
交易一手股票是 100 股
00:22
2023-01-03 09 30 00 - INFO - 开仓数量必须是100的整数倍,调整为 757500
00:12
Order(security=000001.XSHE
00:16
Order() 负责下单交易
00:25
security=000001.XSHE
00:08
style=MarketOrderStyle
00:17
side=long
00:08
下单检查标的数量
00:20
必须检查交易股票数量是否为100的整数倍
00:30
订单已委托
00:12
2023-01-03 15 30 00 - INFO - 函数运行时间(after_market_close):15 30 00
00:16
输出 成交记录
00:18
UserTrade 数据结构
00:11
UserTrade 字典类型数据
00:08
'trade_id' 1695022457
00:07
'order_id' 1695022457
00:07
'time' datetime.datetime
00:14
datetime.datetime(2023, 1, 3, 9, 30)
00:10
'amount' 757500
00:06
'price' 13.22
00:07
一天结束
00:05
##############################################################
00:09
分隔符区分开每天的内容
00:12
一般交易日如果有开仓会有哪些记录
00:12
普通的一天会有哪些交易记录
00:10
大多数时间没有交易记录
00:19
2023-01-04 09 00 00 - INFO - 函数运行时间(before_market_open):09 00 00
00:14
2023-01-04 09 30 00 - INFO - 函数运行时间(market_open):09 30 00
00:20
2023-01-04 15 30 00 - INFO - 函数运行时间(after_market_close):15 30 00
00:31
2023-01-04 15 30 00 - INFO - 一天结束
00:13
2023-01-04 15 30 00 - INFO - ###############################################
00:22
大多数时间既没有开仓,也没有平仓
00:13
2023-02-16 开始有交易
00:26
2023-02-16 09 00 00 - INFO - 函数运行时间(before_market_open):09 00 00
00:11
2023-02-16 09 30 00 - INFO - 函数运行时间(market_open):09 30 00
00:11
2023-02-16 09 30 00 - INFO - 价格低于均价, 卖出 000001.XSHE
00:12
order StockOrder()
00:14
StockOrder() 卖出股票下单
00:37
security = 000001.XSHE
00:08
mode=OrderTargetAmount _amount=0
00:18
style = MarketOrderStyle
00:13
_limit_price=0.0
00:09
side=long action=close
00:09
entrust_time=2023-02-16 09 30 00
00:13
trade price 13.66
00:12
amount 757500 全部卖出股票
00:12
commission : 13451.685000000001
00:11
订单已委托:StockOrder()
00:12
2023-02-16 15 30 00 - INFO - 函数运行时间(after_market_close):15 30 00
00:12
2023-02-16 15 30 00 - INFO - 成交记录
00:14
UserTrade() 包含平仓记录
00:10
'trade_id' 1695022458
00:08
'order_id' 1695022458
00:08
'time' datetime.datetime(2023, 2, 16, 9, 30)
00:08
'amount' - 757500
00:08
'price' - 13.66
00:06
卖出记录也是字典类型数据
00:21
2023-02-16 15 30 00 - INFO - 一天结束
00:07
麻雀虽小五脏俱全
00:19
固定股票品种,没有选择
00:11
择时部分是关键
00:18
直接以 50 日均线做基准
00:17
修改后复合收益率为 6%
02:59
前期介绍的是 聚宽示例代码
00:20
也详细介绍了 聚宽示例 给出的日志信息
00:24
逐个分析重要的系统 API 函数
00:25
获取股票价格函数 get_bars()
00:18
打开 API 文档
00:45
Ctrl + F 打开查询对话框
00:12
查找 get_bars() 函数
00:51
浏览 get_bars() 函数页面
00:19
【API解析】get_bars 定义和逻辑
00:10
get_bars() 有 8 个参数,还比较复杂
00:16
对这 8 个参数逐个进行介绍
00:08
security 股票代码
00:09
第一个参数都是 股票代码
00:22
如何设计 API 和参数
00:15
支持一个或多个标的
00:10
多个标的用list或tuple
00:17
ist 或 tuple
00:09
count 返回bar的个数
00:08
返回bar的个数。设置为 50
00:16
unit bar的划分单位
00:12
支持 ('1m', '5m', '15m', '30m', '60m', '120m', 'xm', '1d', '1w', '1M')
00:15
'1m', '5m', '15m', '30m', '60m', '120m', 'xm' 多少分钟
00:15
'1d'
00:07
'1w' 周线数据
00:08
'1M' 月线
00:07
fields 获取数据的字段
00:07
可以是 OHLC 数据
00:15
'open', 'high', 'low', 'close'
00:10
m 和 M 含义不同,需要注意
00:17
fields=('date' 日期数据可以读取
00:11
'date', 'open', 'high', 'low', 'close'
00:17
fields= 成交量数据也可以观察
00:12
include_now 是否包含end_dt所在的bar
00:15
include_now=False 不包含
00:09
回测时是当时程序运行到的位置
00:16
end_dt 截止时间
00:08
end_dt=None
00:07
fq_ref_date 复权基准日期
00:08
fq_ref_date=None
00:07
df 是否返回pandas.DataFrame对象
00:11
默认为False,返回的是numpy.ndarray对象
00:09
是numpy.ndarray对象
00:17
返回pandas.DataFrame对象
00:10
numpy.ndarray对象。结构简单,计算快
00:14
get_bars 没有跳过停牌选项
00:12
所获取的数据都是不包含停牌的数据
00:10
如果bar个数少于count个
00:08
则返回实际个数,并不会填充
00:07
少于count个,则返回实际个数
00:26
为了方便计算而设计该函数
00:12
返回类型
00:14
df = False 返回结果
00:13
security 为字符串(标的code)时,return numpy.ndarray
00:19
get_bars('000001.XSHE'
00:15
count=2
00:07
end_dt=datetime.datetime.now()
00:10
fields=('date', 'open', 'high', 'low', 'close')
00:11
get_bars('000001.XSHE', count=2, end_dt=datetime.datetime.now(), fields=('dat
00:14
新建代码框
00:31
拷贝代码准备研究
00:14
000001.XSHG 上证综指
00:32
count=5 查看前5天数据
00:12
星号 表示正在运行代码
00:10
得到了数组类型的数据
00:18
datetime.date(2023, 9, 12)
00:16
上证综指的 OHLC 数据
00:19
(datetime.date(2023, 9, 18), 3110.44, 3128.7, 3098.5, 3125.93)
00:19
不包含当前周期的数据
00:13
之前 5 日的行情数据
00:19
不包含当前数据的原因
00:42
security 为字符串list或者tuple
00:10
同时得到多只股票数据
00:09
security 为字符串list或者tuple时,返回dict
00:09
key是 code
00:07
value 是 numpy.ndarray
00:08
返回dict,key是 code, value是numpy.ndarray
00:25
传入参数是证券代码
00:29
get_bars(['000001.XSHE','600000.XSHG']
00:21
['000001.XSHE','600000.XSHG']
00:20
count = 2。两个周期的数据
00:10
end_dt = datetime.datetime.now()
00:08
fields = ('date', 'open', 'high', 'low', 'close')
00:11
拷贝到研究环境中观察
00:12
简单修改代码参数
00:23
前一个 get_bars() 没有返回信息
00:12
返回了正确的结果
00:16
放大网页内容,观察更清晰
00:19
在外部是字典结构数据
00:12
'000001.XSHE' array(
00:18
'600000.XSHG' array(
00:11
股票代码 和 数组数据值
00:11
层层嵌套的复杂数据结构
00:31
df = True
00:17
df = True 获得的时 数据框 类型的数据
00:17
security 为字符串(标的code)
00:08
return pandas.DataFrame
00:08
dataframe 的index是一个整数数组
00:10
索引有明显不同,不是日期时间而是整数
00:25
df=True 其他参数都一样
00:18
get_bars('000001.XSHE', count=2, end_dt=datetime.datetime.now() 拷贝代码
00:15
运行代码得到 数据框
00:23
'000001.XSHG', count=5
00:19
上证综指之前 5 天的行情数据
00:17
df 数据比较方便观察分析
00:21
行索引是正整数
00:21
'000001.XSHG' , count=5
00:12
return pandas.DataFrame
00:08
dataframe 的index是一个MultiIndex
00:12
get_bars(['000001.XSHE' , '600000.XSHG']
00:13
get_bars(['000001.XSHG','600000.XSHG'], count=5 拷贝代码
00:08
get_bars(['000001.XSHG','600000.XSHG'], count=5 代码修改
00:17
get_bars(['000001.XSHG','600000.XSHG'] 运行代码
00:17
分别得到股指和股票数据框
00:19
日期本身就是数据的一部分
00:26
复合索引,证券代码 和 整数索引都有
00:11
get_bars 定义 和 逻辑
00:19
get_bars(security, count, unit='1d'
00:25
count, unit='1d'
00:16
df=False 用于控制返回的数据类型
00:44
核心部分是读取数据的数量
00:34
end_dt 默认值
00:08
end_dt=None
00:12
研究环境中默认为 datetime.datetime.now()
00:11
datetime.datetime.now() 当前时间
00:16
回测 模拟环境中默认为 context.current_dt
00:09
回测 环境中
00:09
模拟环境
00:10
context.current_dt
00:12
context.current_dt 回测经历的日期
00:17
由于bar的最小单位是一分钟
00:10
所以end_dt的秒和毫秒没有什么意义
00:08
end_dt的秒和毫秒没有什么意义,会被替换为0
00:08
end_dt=datetime.datetime(2019, 11, 22, 9, 35, 23)
00:09
end_dt=datetime.datetime(2019, 11, 22, 9, 35, 23) 设置了分钟和秒钟
00:16
和 end_dt=datetime.datetime(2019, 11, 22, 9, 35, 00) 是一样的
00:09
fq_ref_date 复权基准日期
00:19
研究环境中默认为 datetime.date.today()
00:07
datetime.date.today() 今天的日期
00:10
回测 模拟环境中默认为 context.current_dt.date()
00:12
context.current_dt.date() 回测是的日期
00:08
如果用户输入 fq_ref_date = None, 则获取到的是不复权的数据
00:14
如果用户想获取后复权的数据
00:15
可以将fq_ref_date 指定为一个很早的日期
00:11
比如 datetime.date(2000, 1, 1)
00:08
fields 字段
00:05
只支持 ('date', 'open', 'close', 'high', 'low', 'volume', 'money', 'factor', 'o
00:13
其中 open_interest 是期货和期权特有的字段
00:09
'volume' 成交量字段
00:11
'factor' 因子字段
00:06
include_now
00:09
True 表示包含 end_dt 所在的bar
00:09
False表示不包含end_dt 所在的bar
00:06
具体的例子可以看下面 bar的划分方式的例子
00:08
bar的划分方式
00:09
原始数据只存储了1m和1d的bar
00:09
其他unit单位的bar都是根据1m和1d的bar合并而成
00:08
bar的划分单位
00:07
unit 支持 ('1m', '5m', '15m', '30m', '60m', '120m', 'xm', '1d', '1w', '1M')
00:07
unit 为1m
00:09
聚宽分钟bar的时间戳为这一分钟的结束时间
00:08
例如对于股票,一天有240个分钟bar
00:08
第一个分钟bar的时间是09:31
00:11
这样如果输入的end_dt为09 31
00:08
而且include_now=True的时候,会返回09:31这个bar
00:10
get_trades()
00:29
得到当天所有成交记录
00:05
获取成交信息
00:22
获取当天的所有成交记录, 一个订单可能分多次成交
00:10
一个订单可能分多次成交
00:15
参数 无
00:06
返回一个dict
00:06
key是trade_id, value是[Trade]对象
00:07
每个交易日结束运行
00:09
def after_trading_end(context)
00:07
得到当天所有成交记录
00:06
trades = get_trades()
00:08
trades = get_trades() 读取交易记录
00:05
for _trade in trades.values()
00:10
_trade in trades.values()
00:15
trades.values() 枚举字典数据值
00:14
log.info(_trade.trade_id)
00:09
聚宽示例代码 - 介绍完成
00:16
策略评价与建立模拟
00:16
评价策略回测的指标
00:07
评价策略回测的指标 - 举例
00:15
建立模拟交易
00:15
未来函数
00:05
未来函数 - 的含义
00:30
未来函数 危害重大
00:12
运行过慢
00:05
运行过慢 - 含义
00:21
运行过慢 - 模型太复杂
00:09
运行过慢 - 数据结构有关
00:15
运行过慢 - 过度使用循环
00:13
过拟合
00:04
过拟合 - 含义
00:23
策略失效
00:05
策略失效 - 含义
00:32
策略评价与建立模拟 详细介绍
00:11
在学习了如何编写策略后,我们将介绍下评价策略回测的指标
00:09
如何建立模拟交易
00:06
以及除回测之外还有哪些需要关注的方面
00:07
策略回测指标
00:09
一个策略回测后会给出一些指标
00:09
可以在API文档:风险指标
00:11
可以在API文档:风险指标查看这些指标的公式及基本说明
00:10
打开风险指标页面
00:27
风险指标
00:09
风险指标数据有利于您对策略进行一个客观的评价
00:08
回到风险指标的主界面
00:15
查看回测信息
00:15
策略收益
00:07
这是最基础的指标,衡量回测期间策略收益率的
00:08
衡量回测期间策略收益率的
00:22
策略收益率
00:16
基准收益
00:06
基准默认是沪深300指数
00:10
编程时不设置是否会使用?
00:11
删除基准收益相关的代码
00:34
删除基准收益相关内容。还是以沪深300指数为基准
00:28
默认以 沪深300 指数为基准
00:24
所以此指标是回测期间基准收益率的
00:07
所以如果策略收益长期低于基准收益
00:09
往往意味着策略是失败的
00:09
通过set_benchmark()这个API可以自定义基准
00:08
年化收益率
00:08
年化收益率是一个衡量策略盈利能力的重要指标
00:08
衡量策略盈利能力的重要指标,越大越好
00:07
刚刚讲的策略收益这个指标是和回测时间长短强相关的
00:11
比如一个普通策略运行10年肯定比优秀的策略跑半年策略收益高
00:12
普通策略运行10年肯定比优秀的策略跑半年策略 - 未必
00:12
但这样就不利于比较策略的盈利能力
00:11
通过数学方法,把策略收益统一互相化归为一年时间的收益率
00:11
比如10年的变为平均每年的收益率
00:08
年化收益率,平均收益率
00:09
半年的变为以这半年盈利能力运行一年的收益率
00:09
如此一来,让策略盈利能力在比较时有了一个大致等同的时间标准
00:10
大的缩小,小的放大
00:12
年化收益率 是 年均复合收益率
00:12
最大回撤率
00:08
衡量策略风险的重要指标,越小越好
00:08
新手初见这个指标的时候可能会感到一点点的困难
00:08
其实这个指标是对应着一个很自然的想法的
00:07
比如,你现在要实盘用真钱去跟一个策略操作
00:09
而你现在是知道这个策略的过去一段时间的历史收益曲线的
00:09
你觉得你的最大亏损率估计是多少?
00:09
建议读者自己随手画下几条曲线当做历史收益曲线,思考下这个问题
00:11
一个经典的回答就是最大回撤率的含义
00:11
既然我们还在拿历史数据做回测,说明我们应当还是相信历史对未来有指导意义
00:15
那么我现在实盘用真钱去跟策略操作
00:10
接下来我们假设策略收益的未来走势应当是跟历史走势相当的
00:08
历史走势有一直涨的时候,也有一直跌的时候
00:10
那么我实盘跟策略最大亏损率应该就是
00:08
我刚开始跟策略就开始走的跟历史走势中一直跌的那一段那样
00:12
而且是一直跌且跌的最多的那段
00:09
那么历史走势中一直跌且跌的最多的那段跌跌了多少呢
00:09
用人眼一般很容易找到是哪段,而且聚宽的回测图中也标出了
00:11
不过不妨进一步思考下怎么算出最大回撤率
00:09
然后看下文档中的公式说明,看你的结果是否正确
00:07
当然,初学者知道最大回撤率越小越好可能就够了
00:07
但有志者应该借机学习如何思考如何评估风险以及量化风险,因为难度相对不高
00:12
图中给出的例子
00:12
交易次数
00:07
交易次数其实是一个可以初步衡量策略回测结果是否可靠的指标
00:08
过少往往意味着回测结果不可靠
00:07
试想这样一种情况,别人给你推荐一个策略
00:09
策略进行了10年历史数据的回测
00:09
年化收益非常高,最大回撤非常小
00:08
但仔细一看,交易次数只有2次
00:07
此时,你愿意用真金白银去使用这个策略吗?
00:08
你难免会想可能只是这2次操作运气好而已
00:09
这样的回测结果虽好但是不可信不可靠
00:08
其实这基于一个简单统计学思想,样本过少,则统计结果不可靠
00:09
所以足够多的交易次数才能让回测结果有说服力
00:07
目前,回测结果中不能直接看到交易次数了
00:10
可以通过回测结果页面的其他指标中的盈利次数与亏损次数相加得到
00:10
也可以通过回测结果图表下面的每日买卖大致看出
00:08
盈利和亏损次数相加
00:21
交易次数可以看到
00:11
Alpha(阿尔法)与Beta(贝塔)
00:06
在资本资产定价模型(CAPM)中
00:07
投资组合的收益被分为和市场系统风险相关
00:16
市场系统风险无关的部分
00:07
而Beta与Alpha这两个希腊字母则是该模型中的两个重要系数
00:12
分别代表这相关部分与无关部分
00:06
其实策略持有的股票可以看成一个投资组合
00:08
基准收益作为市场系统收益
00:09
Beta则是代表相关部分的策略收益相对市场波动的倍率
00:10
如Beta为2则代表市场涨1%,相关部分的策略收益波动涨大概2%
00:13
统计意义上并非实时精确
00:07
beta为负数代表与市场反向变动
00:08
而Alpha则代表独立于市场波动不受其影响的无关部分的策略收益
00:11
越大越好
00:05
所以如果策略年化收益为负但Alpha为正而且很大
00:18
说明策略有超过市场的盈利能力
00:07
不过策略整体盈利被与市场相关部分拉下来了
00:08
为了便于理解,Alpha与Beta的含义讲的很粗暴
00:09
建议数理基础不错的有志者有空去自学下Alpha与Beta的构造思路与过程
00:11
夏普比率(Sharpe Ratio)
00:07
代表所承担的单位风险所带来的收益
00:08
单位风险所带来的收益,越大越好
00:10
夏普比率是在资本资产定价模型进一步发展得来的
00:12
回测相关的基本参数介绍完成
00:16
建立模拟交易
00:06
之前讲过回测是用历史数据模拟执行策略
00:08
模拟交易是用未来的实际行情模拟执行策略
00:08
因此当策略完善的自以为差不多没什么问题时
00:10
建议建立一个模拟交易观察一段时间
00:07
当作进一步的检验
00:06
建立的模拟交易的方法很简单
00:09
点击回测结果界面
00:13
右上部红色模拟交易按钮
00:08
即可新建模拟交易
00:05
建立模拟交易成功后,点击聚宽导航栏我的交易
00:11
看到策略正在运行
00:12
点击右边的微信通知开关,将OFF调到ON,按照指示扫描二维码,绑定微信
00:16
界面上有微信通知内容
00:09
就能微信接收交易信号了
00:07
当策略买卖操作,微信会收到信号提醒
00:08
买入股票提醒信息
00:10
时间是 2015 年
00:11
自定义消息内容请看API send_message
00:09
API send_message 打开相关界面
00:19
发送自定义消息
00:10
send_message(message, channel='weixin')
00:07
给用户自己发送消息, 暂时只支持微信消息
00:09
message : 消息内容. 字符串
00:13
channel : 消息渠道
00:08
暂时只支持微信:weixin 默认值是 weixin
00:07
返回值 True False
00:06
表示是否发送成功.
00:08
当发送失败时, 会在日志中显示错误信息
00:07
策略评价与建立模拟 - 总结
00:15
本章讲了两项内容
00:16
介绍了多种回测相关的指标
00:10
指标公式详解
00:30
知道指标含义对于我们评估算法质量有重要意义
00:11
建立模拟交易 - 继续测试算法的实战表现
00:26
客服
顶部
赛事库 课堂 2021拜年纪