聚宽
聚宽官网:https://www.joinquant.com
聚宽基础使用
- 每天买100股的平安银行 ```python “”” 每天买100股的平安银行
- 初始化的函数:选定要交易的股票为平安银行
- 每天循环: 买每天买100股的平安银行
- 平安银行的股票代码应是一个全局变量
本质: 初始化+周期循环 “”” from jqdata import *
def initialize(context): “”” 初始化函数,用于初始化全局变量、设置 “”” g.security = “000001.XSHE”
# 定义每天内何时运行
run_daily(period, time='every_bar')
def period(context): “”” 实现买股票的函数 “”” order(g.security, amount=200) # amount买入的股数,要是100的倍数
# 计算股票的收益率,当股票亏损达到1%卖出股票
# 收益率 = (收入 - 成本)/ 成本 --> 收入/成本-1
# 收入:股票的现价 成本:之前持仓的成本
# 通过当前账户信息来反馈一个买卖记录
# 成本
# print(context.portfolio.positions["000001.XSHE"].avg_cost)
cost = context.portfolio.positions["000001.XSHE"].avg_cost
# 收入
price = context.portfolio.positions["000001.XSHE"].price
# 计算收益率
ret = price/cost - 1
# 判断是否亏损
if ret < -0.01:
order_target(g.security, amount=0)
print("止损")
“”” -红色:默认以沪深300指(代表整个市场增长水平) -蓝色:策略收益曲线 “””
<a name="7qaYH"></a>
### 简单量化策略
- 设置股票池为沪深300的所有成分股
- 如果当前股价小于10元/股且当前不持仓,则买入
- 如果当前股价比买入时上涨了25%,则清仓止盈
- 如果当前股价比买入时下跌了10%,则清仓止损
```python
"""
设置股票池为沪深300的所有成分股
如果当前股价小于10元/股且当前不持仓,则买入
如果当前股价比买入时上涨了25%,则清仓止盈
如果当前股价比买入时下跌了10%,则清仓止损
"""
from jqdata import *
# 1.初始化函数
def initialize(context):
# 设置股票池为沪深300的所有成分股
g.security = get_index_stocks("000300.XSHG")
# 2.每个交易日执行一次
run_daily(period, time="every_bar")
def period(context):
tobuy = []
# 筛选每支股票-->遍历出每支股票的股票代码
for stock in g.security:
# 获取股票的开盘价
p = get_current_data()[stock].day_open
# 获取当前账户持有对应股票的股数
amount = context.portfolio.positions[stock].total_amount
# 获取买入时的成本
cost = context.portfolio.positions[stock].avg_cost
# 如果当前股价比买入时上涨了25%,则清仓止盈
if amount > 0 and p >= cost * 1.25:
order_target(stock, 0)
if amount > 0 and p <= cost * (1-0.1):
order_target(stock, 0)
# 如果当前股价小于10/股且当前不持仓,则买入
if p <= 10 and amount == 0: # 股票价格即小于10且未持仓
tobuy.append(stock)
# 将当前账户信息可用资金 除以tobuy长度 ==> 为每支股票可花的钱
cash_per_stock = context.portfolio.available_cash / len(tobuy)
# 循环取出tobuy每支股票,然后进行下单
for stock in tobuy:
order_value(stock, cash_per_stock)
双均线分析
均线
对于每一个交易日,都可以计算出前N天的移动平均值,然后把这些移动平均值连起来,成为一条线,就叫做N日移动平均线。移动平均线常用:5天,10天,30天,60天,120天和240天的指标
死亡交叉
短期均线下穿长期均线,卖出信号
# 导入函数库
from jqdata import *
# 初始化函数,设定基准等等
def initialize(context):
# 初始化股票代码
g.security = ["000001.XSHE"]
# 初始化天数
g.d5 = 5
g.d60 = 60
run_daily(period, time="every_bar")
def period(context):
"""
双均线策略
金叉买入, 死叉卖出
"""
for stock in g.security:
# 构建MA5以及MA60数据
# MA5: 第一天~第五天的平均价格
# MA60: 第一天~第60天的平均价格
df_5 = attribute_history(stock, g.d5)
df_60 = attribute_history(stock, g.d60)
# 求均值
MA_5 = df_5["close"].mean()
MA_60 = df_60["close"].mean()
"""
- 判断金叉和死叉
- 金叉: 短期均线上穿长期均线 ==> 前一天MA5<MA60并且后一天MA_5>=MA60
- 死叉: 短期均线下穿长期均线 ==> 前一天MA5>MA60并且后一天MA_5<=MA60
- 由于金叉跟死叉是交替出现,
- 如果是金叉买入,死叉全部卖出,
- 因此当MA5>MA60且不持仓时,就是金叉。
- 反之,当MA5<MA60且持仓时,就是死叉。
"""
# 金叉
if MA_5 > MA_60 and stock not in context.portfolio.positions:
order(stock, context.portfolio.available_cash)
# 死叉:
if MA_5 < MA_60 and stock in context.portfolio.positions:
order_target(stock, 0)
# 显示均线图
record(ma_5=MA_5, ma_60=MA_60)
因子选股策略
- 因子:选择股票的某种标准
- 增长率、市值、市盈率、ROE(净资产收益率)
- 选股策略:
- 对于某个因子,选取表现最好(因子最大或最小)的N支股票持仓
- 每隔一段时间调仓一次
- 选股策略一般都是长期的投资,因为不是一天交易一次 而是几个月交易一次
- 小市值策略:选取股票池中市值最小的N只股票持仓 ```python “”” 根据市值做因子策略
- 市值属于财务数据
- 每隔一个月就要将股票池中市值大的卖掉,买入市值小的 “””
导入函数库
from jqdata import *
初始化函数,设定基准等等
def initialize(context):
A股指数成分股
g.security = get_index_stocks(“000002.XSHG”)
查询财务数据
在数据字典->股票数据->搜索市值,找到markey_cap,这就是股票的总市值
因此搜索的表就是:valuation表中的market_cap
构建get_fundamentals中的query对象
g.q = query(valuation).filter(valuation.code.in_(g.security)) # 查询code在股票池中的valuation表
g.N = 20 # 初始化股票数量
每月执行策略函数
run_monthly(handle_month, 1) # 1=每月第一个交易日
def handle_month(context):
# 获取市值最小的20支股票
# 在财务数据中获取两列:code,market_capp
df = get_fundamentals(g.q)[["code", "market_cap"]]
# 获取到数据后,对market_cap进行升序排序,然后切片
df = df.sort_values("market_cap").iloc[:g.N, :]
# 调仓,持有的股票在df里面就保留,如果在df里面但又没持有则买入
to_hold = df["code"].values
# 遍历现在所持有的所有股票
for stock in context.portfolio.positions:
# 如果持有股票没在to_hold列表里,就卖掉
if stock not in to_hold:
order_target(stock, 0)
# 买入的股票:在to_hold里面,但不在我持有的股票列表里面
tobuy = [stock for stock in to_hold if stock not in context.portfolio.positions]
# 计算每只股票可以使用的资金
# 但要注意,tobuy的长度很有可能为0,所以需要做判断
if len(tobuy) > 0:
cash_per_stock = context.portfolio.available_cash/len(tobuy)
for stock in tobuy:
order_value(stock, cash_per_stock)
<a name="NvLry"></a>
### 多因子选股策略
**综合多个因子:**市值,市盈率,ROE(净资产收益率)等等
<a name="ZLT04"></a>
#### 评分模型:
- 每个股票针对每个因子进行评分,将**评分相加**
- 选出总评分最大的N只股票持仓
- 如何计算股票在某个因子下的评分:归一化(标准化)
<a name="YMJHQ"></a>
### 标准化(归一化:数据预处理)
<a name="oVVCK"></a>
#### min-max标准化:**x* = (x-min)/(max-min)**
- 将原始数据转化为一个0到1的数
- 缺点:如果有新数据加入,可能导致min和max的变化
<br />
<a name="8yKKL"></a>
#### Z-score标准化:x* = (x-μ)/σ
- μ一组数的平均值 σ为标准差
- 将原始数据转化为均值为0,标准差为1的正态分布的随机变量
```python
# 导入函数库
from jqdata import *
"""
ROE(市盈率) - 市值=越大越好
"""
# 初始化函数,设定基准等等
def initialize(context):
# 初始化股票池
g.security = get_index_stocks("000002.XSHG")
# 获取财务数据中的市值和ROE(市盈率)
# 市值=valuation表中的market_cap
# ROE = indicator表中的roe
g.q = query(valuation, indicator).filter(valuation.code.in_(g.security))
# 执行函数
run_monthly(handle_month, 1)
# 循环执行函数
def handle_month(context):
df = get_fundamentals(g.q)[["code", "market_cap", "roe"]]
# 市值与ROE的值相差太大,因此需要先做归一化(0-1)
# 公式 (x-min)/(max-min)
df["market_cap"] = (df["market_cap"] - df["market_cap"].min()) / (df["market_cap"].max() - df["market_cap"].min())
df["roe"] = (df["roe"] - df["roe"].min()) / (df["roe"].max() - df["roe"].min())
df["score"] = df["roe"] - df["market_cap"]
# 选择前20个综合指标优良的股票
df = df.sort_values("score", ascending=False).iloc[:20, :]
# 获取优良股票的代码
to_hold = df["code"].values
# 检查目前账户所持有的股票
for stock in context.portfolio.positions:
# 将持有的股票,但不在优良股票(to_hold)列表的股票清仓
if stock not in to_hold:
order_target(stock, 0)
# 买入在to_hold里面,但是不在我持有的股票列表里面的股票
tobuy = [stock for stock in to_hold if stock not in context.portfolio.positions]
if len(tobuy) > 0:
cash_per_stock=context.portfolio.available_cash/len(tobuy)
for stock in tobuy:
order_value(stock, cash_per_stock)
均值回归理论
均值回归:“跌下去的迟早要涨上来”
均值回归的理论基于以下观测
价格的波动一般会以它的均线为中心。也就是说,当标的价格由于波动而偏离移动均线时,它将调整并重归于均线
定义偏离程度:(MA-P)/MA
均值回归策略执行
- 计算股票池中所有股票的N日均线
- 计算股票池中所有股票与均线的偏离度
- 选取偏离度最高的M支股票并调仓(是否风险最大) ```python from jqdata import *
def initialize(context): g.security = “600036.XSHG”
# 择时
run_daily(period,time="every_bar")
def period(context):
# 压力线 支撑线 (a.mean()-2*a.std(),a.mean()+2*a.std())
# 求20日均线
sr = attribute_history(g.security,20)["close"]
# 求均值
ma_20 = sr.mean()
# 求标准差
std_20 = sr.std()
# 压力线
up_line = ma_20 + 2 * std_20
# 支撑线
down_line = ma_20 - 2 * std_20
# 当当前价格 突破了 上线 则卖出 跌破了下线 买入
p = get_current_data()[g.security].day_open
# 当前可用资金
cash = context.portfolio.available_cash
if p < down_line and g.security not in context.portfolio.positions:
order_value(g.security,cash)
elif p > up_line and g.security in context.portfolio.positions:
order_target(g.security,0)
<a name="MlZ0a"></a>
### 布林带策略
<a name="B9EKb"></a>
#### 布林带策略定义
布林带/布林线/保利加(Bollinger Band)通道策略:由三条轨道线组成,其中上下两条线分别可以看成是价格的压力线和支撑线,在两条线之间是一条价格平均线。<br />
<a name="bvAAV"></a>
#### 计算公式
- 压力线 = M日均线 + N*STD
- 支撑线 = M日均线 - N*STD
- STD为标准差
- N为参数,意味着布林带宽度
```python
"""
布林带
"""
from jqdata import *
def initialize(context):
g.security = get_index_stocks("000300.XSHG")
g.ma_days = 30
run_monthly(handle_month,1)
def handle_month(context):
# 索引:股票代码 值:偏离率
sr = pd.Series(index=g.security)
for stock in sr.index:
# MA30
ma = attribute_history(stock,g.ma_days)["close"].mean()
# 获取当天价格
p = get_current_data()[stock].day_open
# 偏离率
ratio = (ma-p)/ma
sr[stock] = ratio
# 从sr里面选择 10个 最大的选出来
to_hold = sr.nlargest(10).index.values
# print(to_hold)
# 目前账户所持有的股票
for stock in context.portfolio.positions:
# 不再to_hold 股票 给 卖掉
if stock not in to_hold:
order_target(stock,0)
# 买入 在to_hold里面 但是不在我持有的股票列表里面
tobuy = [stock for stock in to_hold if stock not in context.portfolio.positions]
if len(tobuy) > 0:
cash_per_stock = context.portfolio.available_cash/len(tobuy)
for stock in tobuy:
order_value(stock,cash_per_stock)
PEG策略
彼得林奇:任何一家公司股票如果定价合理的话,市盈率就会与收益增长率相等。这就是PEG估值法。
市盈率
市盈率是当前股价(P)相对每股收益(EPS)的比值
- 市盈率(PE) = 股价(P) / 每股收益 (EPS)
- 股价*股数 ≈ 市值
- 每股收益*股数 ≈ 净收益
- 市盈率 ≈ 市值 / 净收益
收益增长率
PEG策略
PEG策略重要条件为:市盈率会与收益增长率相等。也就是PE = G,则得出公式:
由此可以得出结论:
- PEG越低,代表股价被低估的可能性越大,股价会涨的可能性越大。
- PEG是一个综合指标,既考察价值,又兼顾成长性。PEG估值法适合应用于成长型的公司
PEG策略执行思路
PEG策略(选股):
- 计算股票池中所有股票的PEG指标
- 选择PEG最小的N只股票调仓(小的买入,大的卖出)
注意:过滤掉市盈率或收益增长率为负的数据。
"""
PEG策略
"""
from jqdata import *
def initialize(context):
g.security = get_index_stocks("000300.XSHG")
# 市盈率 净利润同比增长率 财务数据 query对象
# pe_ratio 所属表:valuation
# inc_net_profit_year_on_year 所属表:indicator
g.q = query(valuation.code,valuation.pe_ratio,indicator.inc_net_profit_year_on_year).filter(valuation.code.in_(g.security))
run_monthly(handle_month,1)
def handle_month(context):
# 获取财务数据
df = get_fundamentals(g.q)
# print(df)
# 选出 PE 并且 G 都大于 0 的数据
df = df[(df["pe_ratio"]>0) & (df["inc_net_profit_year_on_year"]>0)]
# 计算PEG
df["peg"] = df["pe_ratio"]/df["inc_net_profit_year_on_year"]*100
# 排序 选出最小的
df = df.sort_values("peg")
# 取前20支股票的code 放到 tohold 中
to_hold = df["code"][:20].values
# print(to_hold)
# 目前账户所持有的股票
for stock in context.portfolio.positions:
# 不再to_hold 股票 给 卖掉
if stock not in to_hold:
order_target(stock,0)
# 买入 在to_hold里面 但是不在我持有的股票列表里面
tobuy = [stock for stock in to_hold if stock not in context.portfolio.positions]
if len(tobuy) > 0:
cash_per_stock = context.portfolio.available_cash/len(tobuy)
for stock in tobuy:
order_value(stock,cash_per_stock)