python金融量化分析 | 闲杂笔记

最近事情好像有点多,处理得心不在焉。之前国庆计划把张五常老师的经济解释卷二看完,但也是只把第三章生产的成本看了一下,哈哈~

这是一篇python金融量化分析的闲杂且入门的笔记,感觉学习价值较低,我只是记一下我码的代码,怎么说。我也是刚刚接触这一块,后面有时间再看看书深入学习一下吧~

1 金融基础再基础的粗略介绍

(1)金融:金融就是对现有资源进行重新整合之后,实现价值和利润的等效流通。

(2)金融工具:金融工具是在金融市场中可交易的金融资产。主要分为股票、期货、黄金、外汇、基金、债券等。

(3金融分析:

  • 基本面分析
  1. 行业分析
  2. 公司分析:财务数据、业绩报告等
  3. 宏观经济面分析:国家的财政政策、货币政策等
  • 技术面分析
    1. K线
    2. MA(均线,moving avg)
    3. MACD(指数平滑移动平均线)
    4. KDJ(随机指标)
    5. RSI
    6. BOLL

(4)为什么需要量化交易?

  • 金融量化分析主要是指以先进的数学模型替代人为的主观判断,利用计算机技术从庞大的历史数据当中选出能够带来超额收益的多种“大概率”事件以此来指定策略。

  • 主要就是以下几步:灵光乍现、细化策略、策略转程序、检验策略结果、回测、模拟交易、实盘交易

  • 量化交易的价值:

    1. 避免主观情绪、人性弱点和认知偏差,选择更加客观
    2. 能同时包括多角度的观察和多层次的模型
    3. 及时跟踪市场变化,不断发现新的统计模型,寻找交易机会
    4. 在决定投资策略后,能通过回测验证其效果。

(5)金融书籍推荐

  1. 入门的金融知识应该掌握
  2. 基础的财务知识也要掌握
  3. 徐高 金融经济学25讲 (B站有男神的视频)
  4. 索罗斯 金融炼金术
  5. 马尔基尔 漫步华尔街

PS. 这是本人的一些认识。此外我也是刚刚入门

下面是一些常用的量化平台使用介绍

2 Tushare

2.1 Tushare介绍

(1)Tushare pro是一个python财经数据接口包,说明文档很详细,可以通过文档学习。不过现在开始要积分了呀~

(2)主要实现对股票等金融数据从数据采集、清洗加工 到 数据存储的过程,能够为金融分析人员提供快速、整洁、和多样的便于分析的数据,为他们在数据获取方面极大地减轻工作量,使他们更加专注于策略和模型的研究与实现上。

(3)考虑到Python pandas包在金融量化分析中体现出的优势,Tushare返回的绝大部分的数据格式都是pandas DataFrame类型,非常便于用pandas/NumPy/Matplotlib进行数据分析和可视化

(4)安装:pip install tushare/ 访问https://pypi.python.org/pypi/Tushare/下载安装

(5)学习文档:https://tushare.pro/

2.2 Tushare基础使用

  1. 用户注册:https://tushare.pro/register?reg=379314
  2. 获取token
  3. 初始化接口,调取数据
import tushare as ts
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
# 方法1
# ts.set_token('你的token')
# pro = ts.pro_api()
# 方法2
pro = ts.pro_api('你的token')
# 基本使用
# 使用tushare 获取五粮液股票的历史行情数据
# 输出该股票所有收盘比开盘上涨3%以上的日期
# 输出该股票所有开盘比前日收盘跌幅超过2%的日期
# 假如我从2010年1月1日开始,每月第一个交易日买入1手股票,每年最后一个交易日卖出所有股票。到今天为止,我的收益如何?
# 使用tushare 获取五粮液股票的历史行情数据
# 学习于:https://tushare.pro/document/2?doc_id=27
wly_stock = pro.daily(ts_code="000858.SZ",start_date="20000101")
wly_stock.info()
wly_stock.head()
"""
将数据 保存为csv文件
"""
wly_stock.to_csv("000858.csv",index=False)

"""
读取五粮液文件数据,指定trade_date为时间序列索引。
- parse_dates  设置索引为时间序列索引。注意:类型-->list
"""
wly_df = pd.read_csv("000858.csv",index_col="trade_date",parse_dates=["trade_date"])
wly_df.info()
wly_df.head()
# 输出该股票所有收盘比开盘上涨3%以上的日期
"""
(close - open)/open>0.03 日期
"""
wly_df[(wly_df["close"]- wly_df["open"])/wly_df["open"]>0.1].index
# 输出该股票所有开盘比前日收盘跌幅超过2%的日期
"""
(开盘 - 前日收盘)/前日收盘
"""
wly_df[(wly_df["open"]-wly_df["close"].shift(-1))/wly_df["close"].shift(-1)>=0.02].index
# 假如我从2010年1月1日开始,每月第一个交易日买入1手股票,每年最后一个交易日卖出所有股票。到今天为止,我的收益如何?
"""
得出信息:
- 每月第一个交易日买入:1.支出  2.支出的是每月第一个交易日该股票的开盘价*1手 
- 每年最后一个交易日卖出:2.收入 2.收入的是每年最后一个交易日该股票的开盘价*12手
"""

# 截取 2010开始 2019年结束
# wly_df["2010":"2019"]    # 注意:为空,时间序列连续切片也是有序的
wly_df2 = wly_df["2019":"2010"]      
# 每月第一个交易日数据   first()取每个月中第一个交易日的数据
wly_monthly_f = wly_df2.resample("MS").first()
wly_monthly_f.head()
# 每年最后一个交易日数据
wly_yearly_l = wly_df2.resample("A").last()
wly_yearly_l.head()
"""
收益 = 收入 - 成本
"""
# 初始化 每个月需要购买股票所花的成本 
cost_money = 0

# 初始化 已持有的股票
hold = 0

#  获取 2010-2019 年 每一年 所有的 成本 以及收入 
for year in range(2010,2019):
    cost_money = wly_monthly_f[str(year)]["open"].sum()*100  # 每年每个月初买100手花的钱
    hold = len(wly_monthly_f[str(year)])*100 # 一年持有的股票
    
    sell_money = wly_yearly_l[str(year)]["open"].values[0]*hold # 年末卖出的价格*所卖出的股数
    cost_money -= sell_money
    hold = 0  # 卖出去,所以归为0
    print(cost_money)

# 成本-收入 = -收益
print(f"save_money:{-cost_money},hold:{hold}")

2.3 Tushare进阶使用

2.3.1双均线分析

对于每一个交易日,都可以计算出前N天的移动平均值,然后把这些移动平均值连起来,成为一条线,就叫做N日移动平均线。
移动平均线常用:5天,10天,30天,60天,120天和240天的指标

  1. 5天和10天的是短线操作的参照指标,称做日均线指标;
  2. 30天和60天的是中期均线指标,称做季均线指标;
  3. 120天和240天的是长期均线指标,称做年均线指标。

2.3.2黄金交叉

短期均线上穿长期均线,买入信号
在这里插入图片描述

2.3.3 死亡交叉

短期均线下穿长期均线,卖出信号
在这里插入图片描述

2.3.4 双均线分析练习

  1. 使用tushare包获取某股票的历史行情数据
  2. 使用tushare包计算该股票历史数据的5日均线和30日均线
  3. 使用matplotlib包可视化历史数据的收盘价和两条均线
  4. 分析输出所有金叉日期和死叉日期
  5. 假如我从2010年1月1日开始,初始资金为10W,金叉尽量买入,死叉全部卖出,则到今天为止。我的炒股收益率如何?
# 使用tushare包获取某股票的历史行情数据
# 初始化pro接口
pro = ts.pro_api('b003e7cabaa5ed2b7562426afe5e9802608f6c68563cb0f01290e91f')
pro
# 获取云南白药 2010年 至今的数据
by_stock = pro.daily(ts_code="000538.SZ",start_date="20100101")
# 保存至csv
by_stock.to_csv("000538.csv",index=False)
# 读取云南白药的数据 
by_df = pd.read_csv("000538.csv",index_col="trade_date",parse_dates=["trade_date"])[["open","high","low","close"]]
by_df.head()

# 时间升序
by_df.sort_index(inplace=True)
# 使用tushare包计算该股票历史数据的5日均线和30日均线
# 添加 MA5,MA30 两列 赋值为nan
by_df["MA5"] = np.nan
by_df["MA30"] = np.nan
by_df.head()
"""
MA5 
需求:0~4 1~5 2~6...
规律:定义一个变量i i的取值范围为4~len(by_df)。i-4~i+1  
"""
for i in range(4,len(by_df)):  # 从样本的第5个值才开始计算
    # 获取MA5列i行的值 赋值为 收盘价的5日均价 
    by_df.loc[by_df.index[i],"MA5"] = by_df["close"][i-4:i+1].mean()  #  取头不取尾

"""
MA30 
需求:0~29 30~59 59~89...
规律:定义一个变量i i的取值范围为4~len(by_df)。i-4~i+1  
"""
for i in range(29,len(by_df)):
    # 获取MA30列i行的值 赋值为 收盘价的30日均价 
    by_df.loc[by_df.index[i],"MA30"] = by_df["close"][i-29:i+1].mean()

by_df.head()
# """
# 法2:rolling实现
# """
# by_df["close"].rolling(5).mean()
# by_df["close"].rolling(30).mean()
by_df[["close","MA5","MA30"]].plot()
plt.show()

在这里插入图片描述

# 分析输出所有金叉日期和死叉日期
# 清洗nan的值
by_data = by_df.dropna()
by_data.info()
by_data.head()
"""
法1:
- 金叉 : 短期均线 上穿 长期均线 --> 前一天 MA5<=MA30 并且 后一天MA5>=MA30
- 死叉 : 短期均线 下穿 长期均线 --> 前一天 MA5>=MA30 并且 后一天MA5<=MA30
"""
golden_cross = []
death_cross = []

for i in range(1,len(by_data)):
    # 金叉 
    if by_data["MA5"][i] >= by_data["MA30"][i] and by_data["MA5"][i-1] <= by_data["MA30"][i-1]:
        # 将 金叉 的时间 构建成列表
        # print(by_data.index[i])
        golden_cross.append(by_data.index[i])
        
    # 死叉
    if by_data["MA5"][i] <= by_data["MA30"][i] and by_data["MA5"][i-1] >= by_data["MA30"][i-1]:
        # 将 死叉 的时间 构建成列表
        death_cross.append(by_data.index[i])
    
print(golden_cross)
print(death_cross)
"""
方法2
以金叉为例
- 短均比长均波动大
- 短均上穿长均 为 金叉
- 金叉跟死叉交替出现

死叉过度到金叉
- MA5<MA30    TTTTFFFF->TF则为金叉点

如:
<  TTTTFFFF
>  FFFFTTTT

<  TTTTFFFF
>   FFFFTTTT

两个都是F的时候 金叉
两个都是T的时候 死叉
"""
se1 = by_data["MA5"] < by_data["MA30"]
se2 = by_data["MA5"] >= by_data["MA30"]
"""
两个都是F的时候 金叉    
"""
golden_cross2 = by_data[~(se1 | se2.shift(1))].index  #  ma5大于ma30,或者前一天的ma5小于ma30
"""
两个都是T的时候 死叉
"""
death_cross02 = by_data[se1 & se2.shift(1)].index  #  ma5小于ma30,并且前一天的ma5大于等于ma30
# 假如我从2010年1月1日开始,初始资金为10W,金叉尽量买入,死叉全部卖出,则到今天为止。我的炒股收益率如何?
sr1 = pd.Series(1,index=golden_cross2) # 1代表 金叉
sr2 = pd.Series(0,index=death_cross02) # 0代表 死叉
"""
sr1 sr2拼接至一个series对象 
"""
sr = sr1.append(sr2).sort_index()
sr
money = 100000 # 起始资金
hold = 0 # 持有股

for i in range(0,len(sr)):
    """
    买卖需要价格
    - 获取open这列
    - 再通过取出sr的时间索引获取对应的时间价格
    """
    p = by_data["open"][sr.index[i]]
     # 并不确定这个循环的点 是死叉还是金叉
    # 判断 如果说,该索引对应的值为1的时候 金叉 买入
    if sr.iloc[i] == 1:
        # 金叉
        buy = money//(100*p) # 买入多少股 100的倍数
        hold += buy*100      # 一共持有多少股
        money -= buy*100*p   # 买入了,起始资金会减少
    else:
        # 死叉 卖出
        money += hold*p      # 卖出就说明,资金变多了
        hold = 0
        
"""
注意:
如果最后一个点是金叉点 买入 所花的这笔钱 也算作 你的收入
"""
money

3 聚宽

聚宽官网:https://www.joinquant.com
有比较详细的介绍,不想描述了
以下代码均为在聚宽策略上的测试

3.1 聚宽基础使用-买入股票

# 聚宽基础使用
# • 每天买100股的平安银行
'''
聚宽的基础使用
每天买100股的平安银行股票
'''

# 1.初始化函数
def initialize(context):
    # 初始化股票代码、全局变量、为平安银行;多支股票则可指定为列表
    g.security = "000001.XSHE"
    
    #初始化定时运行策略
    run_daily(period,time="every_bar")
    

# 2.定时执行策略函数
def period(context):
    # 每天买入100股,下单函数:API搜value --> 策略API介绍/交易函数
    # 注意:因为买入的单位为100股的倍数,所以就算买的是130股,也会调整为每天买入100股
    order(g.security,100)  
    
    # 计算该股票收益率,当股票亏损达到1%时,则卖出股票,幅度自己调整
    # 获得股票的持仓成本
    cost = context.portfolio.positions["000001.XSHE"].avg_cost
    
    # 获得股票现价
    price = context.portfolio.positions["000001.XSHE"].price
    
    # 计算收益率
    ret = price/cost - 1
    
    # 如果收益率小于-0.01,即亏损达到1%则卖出股票
    if ret<-0.01:
        order_target('000001.XSHE',0) 

3.2 合适时机入仓及清仓

# 简单量化策略
# 设置股票池为沪深300的所有成分股
# 如果当前股价⼩于10元/股且当前不持仓,则买⼊
# 如果当前股价⽐买⼊时上涨了25%,则清仓⽌盈
# 如果当前股价⽐买⼊时下跌了10%,则清仓⽌损
# 导入函数库
from jqdata import *

# 1.初始化函数
def initialize(context):
    # 设置股票池为沪深300的所有成分股
    g.security = get_index_stocks("000300.XSHG")
    
    # 每个交易日执行一次
    run_daily(period,time="every_bar")


# 2.每个交易日执行一次的函数
def period(context):
    # 初始化tobuy
    tobuy = []
    
    # 筛选每支股票 --> 遍历出每支股票的股票代码
    for stock in g.security:
        """
        2. 如果当前股价小于10元/股且当前不持仓,则买入
        - 每股开盘价
        - 是否持仓
        """
        # 获取当前股票的开盘价
        p = get_current_data()[stock].day_open
        
        # 获取当前股票持有股数
        amount = context.portfolio.positions[stock].total_amount
        
        # 买的时候成本价格
        cost = context.portfolio.positions[stock].avg_cost
        
        # 3. 如果当前股价⽐买⼊时上涨 25% ,则清仓⽌盈
        if amount > 0 and p>= cost*(1+0.25):
            order_target(stock,0)
        
        # 4.如果当前股价⽐买⼊时下跌了 10% ,则清仓⽌损
        if amount > 0 and p<= cost*(1-0.1):
            order_target(stock,0)
        
        # 2.如果当前股价<10元 且 当前不持仓 则买入
        if p <= 10 and amount == 0:
            # 一共100000 要分给 300支股票 
            # 将符合买入条件的股票 存储到tobuy列表里
            tobuy.append(stock)
    
    # 2. 将可⽤的钱 除以 需要购买股票的⻓度 为每⽀股票可花的钱
    cash_per_stock = context.portfolio.available_cash / len(tobuy)
    
    # 2. 循环出 可买股票的代码
    for stock in tobuy:
        # 将可买股票的钱 购买它
        order_value(stock,cash_per_stock)

3.3 双均线分析

"""
黄金交叉:短期均线上穿⻓期均线,买⼊信号
死亡交叉:短期均线下穿⻓期均线,卖出信号
"""

from jqdata import *

# 1 初始化函数
def initialize(context):
    # 初始化全局变量 : 股票代码
    g.security = ["601318.XSHG"]
    
    # 初始化全局变量:天数
    g.d5 = 5
    g.d60 = 60
    
    # 初始化交易函数
    run_daily(handle_daily,time="every_bar")
    

# 2 定义每个交易日执行函数
def handle_daily(context):
    """
    实现:金叉买入,死叉卖出
    """
    # 循环遍历股票
    for stock in g.security:
        # 构建5日及60日均线 
        df_5 = attribute_history(stock,g.d5)
        df_60 = attribute_history(stock,g.d60)
        # print(df_5)
        # print(df_60)
        
        # 求均值
        MA_5 = df_5["close"].mean()
        MA_60 = df_60["close"].mean()
        
        # 判断金叉死叉
        # ⾦叉:短上穿⻓,前⼀天: 5MA<60MA 并且5MA>=60MA
        # 死叉:短下穿⻓,前⼀天: 5MA>60MA 并且5MA<=60MA
        # ⾦叉死叉肯定是交替出现的 并且 ⾦买 死卖
        # ⾦叉: MA5>MA60 并且 不持仓
        # 死叉: MA5<MA60 并且 持仓
        
        # 死叉
        if MA_5 < MA_60 and stock in context.portfolio.positions:
            # 清仓卖出
            order_target(stock,0)
        
        # 金叉
        if MA_5 > MA_60 and stock not in context.portfolio.positions:
            # 只买一支股票,不用担心配资。有多少可使用资金则买多少
            order(stock,context.portfolio.available_cash)
            
        # 显示线性图
        record(ma_5=MA_5,ma_60=MA_60)

3.4 因子选股策略

  • 因子:选择股票的某种标准
    1.增长率、市值、市盈率、ROE(净资产收益率)
  • 选股策略:
    1.对于某个因子,选取表现最好(因子最大或最小)的N支股票持仓
    2.每隔一段时间调仓一次
    3.选股策略一般都是长期的投资,因为不是一天交易一次 而是几个月交易一次

3.4.1 小市值策略

小市值策略:选取股票池中市值最小的N只股票持仓

# 导入函数库
from jqdata import *

# 1.初始化函数
def initialize(context):
    # 初始化全局变量:A股指数 数据池
    g.security = get_index_stocks("000002.XSHG")
    
    # 查询的市值对象 为后续获取市值数据做准备
    # select market_cap from valuation where code in g.security
    g.q = query(valuation).filter(valuation.code.in_(g.security))
    g.N = 20
    
   
    # handle_month每月执行一次  注意:1不是第一天 而是第一个交易日
    run_monthly(handle_month,1)   
    
    
# 2.每月第一个交易日调用一次
def handle_month(context):
 	# 2.1 获取A股指数 市值最小的20支股票 
    # 通过get_fundamentals 获取对应股票代码(code)、总市值(market_cap) 
    df = get_fundamentals(g.q)[["code","market_cap"]]
    
    # 对值进行升序排序 --> 将市值较小的 前g.N行切出来
    df = df.sort_values("market_cap").iloc[:g.N,:]
    print(df)
    
    # 2.2 调仓 持有的股票在df(前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]
    
    # 计算每支股票可以使用的钱 但注意: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)

3.4.2 多因子选股策略

综合多个因子:市值,市盈率,ROE(净资产收益率)等等

构建评分模型步骤:

  1. 每个股票针对每个因子进行评分,将评分相加
  2. 选出总评分最大的N只股票持仓
  3. 如何计算股票在某个因子下的评分:归一化(标准化)
    在这里插入图片描述
    下面简单基于roe 和 市值两个分析,(roe减去市值,代表其盈利潜质,越大越好)。这里只是一个检验
## 多因子选股策略
"""
roe - 市值,代表盈利潜质,值越大越好
"""

from jqdata import *

# 1 初始化函数
def initialize(context):
    # 初始化股票池
    g.security = get_index_stocks("000002.XSHG")
    
    # 市值,roe --> 查找在哪个表
    # 市值 market_cap 所属表 valuation
    # roe 所属表:indicator
    g.q = query(valuation,indicator).filter(valuation.code.in_(g.security))
    
    # 执行函数
    run_monthly(handle_month,1)
    

# 2 循环执行函数
def handle_month(context):
    # 获取对应 code market_cap roe
    df = get_fundamentals(g.q)[["code","market_cap","roe"]]
    # print(df)
    
    # 市值 与 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())
    # print(df)
    
    
    # roe - market_cap
    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)

4 均值回归理论

简而言之:价格围绕价值波动,当超越价值过高,就回归;当被低估过分,也会回归。
价格的波动一般会以它的均线为中心。也就是说,当标的价格由于波动而偏离移动均线时,它将调整并重归于均线
定义偏离程度:(MA-P)/MA
MA是日平均线,P是股价
在这里插入图片描述

"""
均值回归策略执行
• 计算股票池中所有股票的N日均线
• 计算股票池中所有股票与均线的偏离度
• 选取偏离度最高的M支股票并调仓(是否风险最大)
"""

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)

5 布林带策略

布林带/布林线/保利加(Bollinger Band)通道策略:由三条轨道线组成,其中上下两条线分别可以看成是价格的压力线和支撑线,在两条线之间是一条价格平均线。

• 压力线 = M日均线 + NSTD
• 支撑线 = M日均线 - N
STD
• STD为标准差
• N为参数,意味着布林带宽度
其实这里就是假设价格在这个区间波动,达到这个区间高点,就要下落,及时卖出,降到这个区间的低点,就要回升,及时买入

"""
布林带:
价格是在一个区间波动
支撑线:高点
压力线:低点
"""

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())
    # 求10日均线
    sr = attribute_history(g.security,10)["close"]
    
    # 求均值
    ma_10 = sr.mean()
    
    # 求标准差
    std_10 = sr.std()
    
    # 压力线
    up_line = ma_10 + 2 * std_10
    
    # 支撑线
    down_line = ma_10 - 2 * std_10
    
    # 当当前价格 突破了 上线 则卖出  跌破了下线 买入
    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)

6 PEG策略

彼得林奇:任何一家公司股票如果定价合理的话,市盈率就会与收益增长率相等。这就是PEG估值法。

市盈率:当前股价§相对每股收益(EPS)的比值
在这里插入图片描述
收益增长率
在这里插入图片描述
PEG策略条件为:市盈率会与收益增长率相等。也就是PE = G,则得出公式:
在这里插入图片描述
因此,如果大于1,代表市盈率大于收益增长率,公司被高估,所以不该买入,当小于1,被低估,买入

点评:PEG是一个综合指标,既考察价值,又兼顾成长性。PEG估值法适合应用于成长型的公司

"""
PEG策略执行思路
大于1,代表市盈率大于收益增长率,公司被高估,所以不该买入;
当小于1,被低估,买入
PEG策略(选股):
• 计算股票池中所有股票的PEG指标
• 选择PEG最小的N只股票调仓(小的买入,大的卖出)
注意:过滤掉市盈率或收益增长率为负的数据。
"""

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)

最后总结一句:以上所有策略经检验,都较为失败,跑不赢大盘 ==

  • 0
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值