本次量化的总体思路是:今天以开盘价全仓买入,明天以收盘价全仓卖出
目标股池:股票太多了,就只选沪深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