**

聚宽

聚宽官网:https://www.joinquant.com

聚宽基础使用

  • 每天买100股的平安银行 ```python “”” 每天买100股的平安银行
  • 初始化的函数:选定要交易的股票为平安银行
  • 每天循环: 买每天买100股的平安银行
  • 平安银行的股票代码应是一个全局变量

本质: 初始化+周期循环 “”” from jqdata import *

def initialize(context): “”” 初始化函数,用于初始化全局变量、设置 “”” g.security = “000001.XSHE”

  1. # 定义每天内何时运行
  2. 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天的指标

  • 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

image.png

均值回归策略执行

  • 计算股票池中所有股票的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 />![image.png](https://cdn.nlark.com/yuque/0/2020/png/704747/1602327350949-ddf19910-9db7-45c7-a631-59ac6f390922.png#align=left&display=inline&height=254&margin=%5Bobject%20Object%5D&name=image.png&originHeight=304&originWidth=626&size=175081&status=done&style=none&width=523)
<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)的比值
image.png

  • 市盈率(PE) = 股价(P) / 每股收益 (EPS)
    • 股价*股数 ≈ 市值
    • 每股收益*股数 ≈ 净收益
  • 市盈率 ≈ 市值 / 净收益

收益增长率

image.png

PEG策略

PEG策略重要条件为:市盈率会与收益增长率相等。也就是PE = G,则得出公式:
image.png
由此可以得出结论:

  • 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)