一个简单的量化交易策略

本次量化的总体思路是:今天以开盘价全仓买入,明天以收盘价全仓卖出

目标股池:股票太多了,就只选沪深300里面的300只股票,再每天选出5日均线大于30日均线,rsi指标小于50的股票,再随机选出一只买入

开始之前需要先了解一下聚宽的几个因子函数:MA(),MACD(),RSI()。

def ma(data,time):
    '''传入一个股票列表'''
    '''MA详见ma均线解析:https://www.joinquant.com/help/api/help#technicalanalysis:MA-均线'''
    ma5=MA(      
        security_list=data, #XSHG  上海证券交易所 ; XSHE   深圳证券交易所 
        check_date=time, 
        timeperiod=5, 
        unit = '1d', 
        include_now = True, 
        fq_ref_date = None
        )
    ma30=MA(      
        security_list=data, #XSHG  上海证券交易所 ; XSHE   深圳证券交易所 
        check_date="2023-06-19", 
        timeperiod=30, 
        unit = '1d', 
        include_now = True, 
        fq_ref_date = None
        )
    return ma5,ma30

'''macd的用法: 
1.DIFF、DEA均为正,DIFF向上突破DEA,买入信号。 
2.DIFF、DEA均为负,DIFF向下跌破DEA,卖出信号。
3.DEA线与K线发生背离,行情反转信号。 
4.分析MACD柱状线,由红变绿(正变负),卖出信号;由绿变红,买入信号'''
def macd(data,time):
    macd=MACD(
        security_list=data, 
        check_date=time, 
        SHORT = 12, 
        LONG = 26, 
        MID = 9, 
        unit = '1d', 
        include_now = True, 
        fq_ref_date = None
        )
    return macd[0],macd[1],macd[2]
# print(macd("002129.XSHE")) 

'''用法注释:
1.RSI>80 为超买,RSI<20 为超卖; 
2.RSI 以50为中界线,大于50视为多头行情,小于50视为空头行情; 
3.RSI 在80以上形成M头或头肩顶形态时,视为向下反转信号; 
4.RSI 在20以下形成W底或头肩底形态时,视为向上反转信号; 
5.RSI 向上突破其高点连线时,买进;RSI 向下跌破其低点连线时,卖出。
'''
def rsi(data,time):
    rsi=RSI(
        security_list=data, 
        check_date=time, 
        N1=6, 
        unit = '1d', 
        include_now = True, 
        fq_ref_date = None
        )
    return rsi

获取股票价格的函数:get_price(),如开盘价,收盘价等

'''获取股票的当前价格信息'''
#函数介绍详见https://www.joinquant.com/help/api/help#index:历史行情数据
def fun(data,time):
    df=get_price(
        security=data, 
        start_date=time, 
        end_date=time, 
        frequency='daily', 
        fields=["open", "close"], #要获取的行情数据字段
        skip_paused=False, #是否跳过不交易日期(包括停牌, 未上市或者退市后的日期).
        fq='pre'  #前复权
        )
    return df

有了ma和rsi后,便可以选出沪深300里面ma5>ma30 and rsi<50 的股票list

#根据获取到的m5,m30数据写选股的策略
def yz(data,time):
    ma1=ma(data,time)
    macd1=macd(data,time)
    rsi1=rsi(data,time)
    dict1={
    "证券代码":ma1[0].keys(),
    "ma5":ma1[0].values(),
    "ma30":ma1[1].values(),
    "macd_m":macd1[2].values(),
    "rsi":rsi1.values()
    }
    df=pd.DataFrame(dict1)
    list1=[]
    for i in range(len(df)):
        if df.macd_m[i]>=0 and df.ma5[i]>=df.ma30[i] and df.rsi[i]<50:
            data=df.证券代码[i]
            list1.append(data)    
    return list1

有了可以买入的股票数据后,开始买卖操作,并记录。在此之前,需要先获取一下A股交易日历的数据,我是自己爬的,因为 获取股票价格的函数:get_price()需要传入交易日的日期,否则是没有数据的

'''记录买入信息,买入先看是否是交易日,如果不是则+1为time3'''
def buy(data,k_df):
    zdrq=pd.read_excel(r"A股交易日历.xlsx",index_col=0,dtype={"交易日":str})
    d=zdrq["交易日"].str.contains(k_df["日期"][-1],case=True)
    time3=zdrq.loc[(zdrq[d].index+1).values].values[0][0]
    if not zdrq[d].empty:
        arr=yz(data,time3)
        daima=random.choice(arr)
        #如果当前持仓为0,可用资金大于0,因子函数yz()选出来的arr有股票,则买入,否则当前持仓还是上一日的股票
        if k_df["当前持仓"][-1]==0 and k_df["可用资金"][-1]>0 and len(arr)!=0:
            df1=fun(daima,time3)
            c_w=k_df["可用资金"][-1]/df1.open[0]//100
            money=k_df["可用资金"][-1]-c_w*df1.open[0]*100
            # name=df1.index.values
            k_df.loc[time3]=[time3,df1.open[-1],df1.close[-1],daima,c_w,money,c_w*df1.open[-1]*100+money]
        else :
            df1=fun(k_df.代码[-1],time3)     #如果今天不买入股票,则上一日买入后今天持仓还是一样,所以要取上一日的持仓数据,更新总资产和开盘价和收盘价
            k_df.loc[time3]=[
            time3,                         #传入的交易日时间参数   
            df1.open[-1],
            df1.close[-1],
            k_df.values[-1][3], #k_df的代码列
            k_df.values[-1][4], #k_df的当前持仓列
            k_df.values[-1][5], #k_df的可用资金列
            k_df.values[-1][4]*df1.close[-1]*100+k_df.values[-1][5]
            ]
    else:
        pass
    return k_df


'''记录卖出信息,有仓位时,第二天就卖,因为只有交易日才能买卖,买入的参数是表格里面的,不需要修改。
但是卖出的第二天需要为交易日,所以用s.str.contains找到time1在表格的位置,找到位置后+1就是下一个交易日'''
def sell(k_df):
    zdrq=pd.read_excel(r"D:\0kefu+1\p\量化交易\A股交易日历.xlsx",index_col=0,dtype={"交易日":str})
    if not k_df.empty:  #如果df不为空
        d=zdrq["交易日"].str.contains(k_df["日期"][-1],case=True)
        time3=zdrq.loc[(zdrq[d].index+1).values].values[0][0]
        # time3=pd.to_datetime(df.index.values[0])+pd.Timedelta('1days')
        df1=fun(k_df.代码[-1],time3)
        money=df1.close[0]*k_df["当前持仓"][-1]*100+k_df["可用资金"][-1]
        k_df.loc[time3]=[time3,df1.open[-1],df1.close[-1],k_df["代码"][-1],0,money,money]
    else:
        pass
    return k_df

以下是我运行后的结果,很显然,随机买入卖出,一个月的时间亏了近1万,有了总资产的数据后就可以做收益图,我就不做了,主要交流一下量化的思路

 注意:k_df我创建的一个空表,2023-04-10是初始资金100000,没有持仓,用于记录每一次买卖交易

完整代码:

from jqdatasdk import *
from jqdatasdk.technical_analysis import *
import numpy as np
import pandas as pd
import random

import warnings
warnings.simplefilter('ignore') #pd.read_excel()读沪深300样本股6.9号更新.xlsx成功运行,但是有一个报错。warnings可以防止报错。

#连接聚宽的方式
auth("***************","******")



#run函数用于读取传入股票代码的数据open,close,low等数据。
def ma(data,time):
    '''传入一个股票列表'''
    '''MA详见ma均线解析:https://www.joinquant.com/help/api/help#technicalanalysis:MA-均线'''
    ma5=MA(      
        security_list=data, #XSHG  上海证券交易所 ; XSHE   深圳证券交易所 
        check_date=time, 
        timeperiod=5, 
        unit = '1d', 
        include_now = True, 
        fq_ref_date = None
        )
    ma30=MA(      
        security_list=data, #XSHG  上海证券交易所 ; XSHE   深圳证券交易所 
        check_date="2023-06-19", 
        timeperiod=30, 
        unit = '1d', 
        include_now = True, 
        fq_ref_date = None
        )
    return ma5,ma30

'''macd的用法: 
1.DIFF、DEA均为正,DIFF向上突破DEA,买入信号。 
2.DIFF、DEA均为负,DIFF向下跌破DEA,卖出信号。
3.DEA线与K线发生背离,行情反转信号。 
4.分析MACD柱状线,由红变绿(正变负),卖出信号;由绿变红,买入信号'''
def macd(data,time):
    macd=MACD(
        security_list=data, 
        check_date=time, 
        SHORT = 12, 
        LONG = 26, 
        MID = 9, 
        unit = '1d', 
        include_now = True, 
        fq_ref_date = None
        )
    return macd[0],macd[1],macd[2]
# print(macd("002129.XSHE")) 

'''用法注释:
1.RSI>80 为超买,RSI<20 为超卖; 
2.RSI 以50为中界线,大于50视为多头行情,小于50视为空头行情; 
3.RSI 在80以上形成M头或头肩顶形态时,视为向下反转信号; 
4.RSI 在20以下形成W底或头肩底形态时,视为向上反转信号; 
5.RSI 向上突破其高点连线时,买进;RSI 向下跌破其低点连线时,卖出。
'''
def rsi(data,time):
    rsi=RSI(
        security_list=data, 
        check_date=time, 
        N1=6, 
        unit = '1d', 
        include_now = True, 
        fq_ref_date = None
        )
    return rsi
# print(rsi("002129.XSHE")) 

#根据获取到的m5,m30数据写选股的策略
def yz(data,time):
    ma1=ma(data,time)
    macd1=macd(data,time)
    rsi1=rsi(data,time)
    dict1={
    "证券代码":ma1[0].keys(),
    "ma5":ma1[0].values(),
    "ma30":ma1[1].values(),
    "macd_m":macd1[2].values(),
    "rsi":rsi1.values()
    }
    df=pd.DataFrame(dict1)
    list1=[]
    #选取沪深300里面今天ma5日线大于ma30日线的股票
    # for i in range(len(df)):
    #     if df.ma5[i]>=df.ma30[i]:
    #         data=df.证券代码[i]
    #         list1.append(data)
    #选取沪深300里面今天rsi<=20的股票
    # for i in range(len(df)):
    #     if df.rsi[i]<=20:
    #         data=df.证券代码[i]
    #         list1.append(data)
    #选取沪深300里面今天macd的m值为正;ma5大于ma30的股票(参考东方财富macd指标的m值)
    for i in range(len(df)):
        if df.macd_m[i]>=0 and df.ma5[i]>=df.ma30[i] and df.rsi[i]<50:
            data=df.证券代码[i]
            list1.append(data)    
    return list1


'''获取股票的当前价格信息'''
#函数介绍详见https://www.joinquant.com/help/api/help#index:历史行情数据
def fun(data,time):
    df=get_price(
        security=data, 
        start_date=time, 
        end_date=time, 
        frequency='daily', 
        fields=["open", "close"], #要获取的行情数据字段
        skip_paused=False, #是否跳过不交易日期(包括停牌, 未上市或者退市后的日期).
        fq='pre'  #前复权
        )
    return df

# data=fun("002129.XSHE","2023-06-19")
# print(data.index[-1])
# print(data.open[-1])
# print(data.close[-1])

'''记录买入信息,买入先看是否是交易日,如果不是则+1为time3'''
def buy(data,k_df):
    zdrq=pd.read_excel(r"D:\0kefu+1\p\量化交易\A股交易日历.xlsx",index_col=0,dtype={"交易日":str})
    d=zdrq["交易日"].str.contains(k_df["日期"][-1],case=True)
    time3=zdrq.loc[(zdrq[d].index+1).values].values[0][0]
    if not zdrq[d].empty:
        arr=yz(data,time3)
        daima=random.choice(arr)
        #如果当前持仓为0,可用资金大于0,因子函数yz()选出来的arr有股票,则买入,否则当前持仓还是上一日的股票
        if k_df["当前持仓"][-1]==0 and k_df["可用资金"][-1]>0 and len(arr)!=0:
            df1=fun(daima,time3)
            c_w=k_df["可用资金"][-1]/df1.open[0]//100
            money=k_df["可用资金"][-1]-c_w*df1.open[0]*100
            # name=df1.index.values
            k_df.loc[time3]=[time3,df1.open[-1],df1.close[-1],daima,c_w,money,c_w*df1.open[-1]*100+money]
        else :
            df1=fun(k_df.代码[-1],time3)     #如果今天不买入股票,则上一日买入后今天持仓还是一样,所以要取上一日的持仓数据,更新总资产和开盘价和收盘价
            k_df.loc[time3]=[
            time3,                         #传入的交易日时间参数   
            df1.open[-1],
            df1.close[-1],
            k_df.values[-1][3], #k_df的代码列
            k_df.values[-1][4], #k_df的当前持仓列
            k_df.values[-1][5], #k_df的可用资金列
            k_df.values[-1][4]*df1.close[-1]*100+k_df.values[-1][5]
            ]
    else:
        pass
    return k_df


'''记录卖出信息,有仓位时,第二天就卖,因为只有交易日才能买卖,买入的参数是表格里面的,不需要修改。
但是卖出的第二天需要为交易日,所以用s.str.contains找到time1在表格的位置,找到位置后+1就是下一个交易日'''
def sell(k_df):
    zdrq=pd.read_excel(r"D:\0kefu+1\p\量化交易\A股交易日历.xlsx",index_col=0,dtype={"交易日":str})
    if not k_df.empty:  #如果df不为空
        d=zdrq["交易日"].str.contains(k_df["日期"][-1],case=True)
        time3=zdrq.loc[(zdrq[d].index+1).values].values[0][0]
        # time3=pd.to_datetime(df.index.values[0])+pd.Timedelta('1days')
        df1=fun(k_df.代码[-1],time3)
        money=df1.close[0]*k_df["当前持仓"][-1]*100+k_df["可用资金"][-1]
        k_df.loc[time3]=[time3,df1.open[-1],df1.close[-1],k_df["代码"][-1],0,money,money]
    else:
        pass
    return k_df

if __name__=="__main__":
    k_df=pd.DataFrame(data=None,columns=["日期","open","close","代码","当前持仓","可用资金","总资产"])
    k_df.loc[0,"日期"]="2023-04-10"  #初始仓位
    k_df.loc[0,"当前持仓"]=0  #初始仓位
    k_df.loc[0,"可用资金"]=100000
    k_df.loc[0,"总资产"]=100000  #初始资金
    k_df.set_index("日期",inplace=True,drop=False)
    k_df.index.values[0]="2023-04-10"
    # print(k_df.values)
    df=pd.read_excel(r"D:\0kefu+1\p\tushare\沪深300样本股6.9号更新.xlsx",index_col=0,dtype={"证券代码":str})
    df1=pd.read_excel(r"D:\0kefu+1\p\量化交易\A股交易日历.xlsx",index_col=0,dtype={"交易日":str})
    for i in range(len(df.index.values)):
        if df.index.values[i][0]=="0" or df.index.values[i][0]=="3":
            df.index.values[i]=df.index.values[i]+".XSHE"
        else:
            df.index.values[i]=df.index.values[i]+".XSHG"
    
    '''当i是奇数的时候买入,是偶数的时候卖出,就达到了第一天买入,下一个交易日是卖出'''
    i=1
    for i in range(1,20):
        print(i)
        if i%2!=0:
            buy(list(df.index.values),k_df)
            print(k_df)
        else:
            sell(k_df)
            print(k_df)
        i+=1


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值