import akshare as ak
import time
#import datetime
import numpy as np
from datetime import datetime, timedelta
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
from datetime import datetime
import time
my_sender = '[email protected]' # 发件人邮箱账号
my_pass = 'xxxxxxxxxx' # 发件人邮箱密码
my_user = '[email protected]' # 收件人邮箱账号(这里发自己)
day_nums = 1 #使用前一天的收盘价数据做信号判断
stock_num = 1 # 买入评分最高的前stock_num只股票 可以修改
momentum_day = 20 # 最新动量参考最近momentum_day的
ref_stock = 'sh000300' # 用ref_stock做择时计算的基础数据
N = 18 # 计算最新斜率slope,拟合度r2参考最近N天
M = 600 # 计算最新标准分zscore,rsrs_score参考最近M天
score_threshold = 0.7 # rsrs标准分指标阈值
def get_index_list(index_symbol = 'sh000068'):
stocks2 = []
stocks = ak.index_stock_hist(index_symbol).stock_code
for stock in stocks[:]:
if int(stock) < 100000:
stock = 'sz' + stock
else:
stock = 'sh' + stock
stocks2.append(stock)
return stocks2
stock_pool = get_index_list()
#找到有交易信号的股票,为之后交易进行准备
# 动量因子:由收益率动量改为相对MA90均线的乖离动量
def get_rank(stock_pool):
rank, biasN = [], 90
for stock in stock_pool:
#print(stock)
from_date = '2010-01-01'
from_date = datetime.strptime(from_date,"%Y-%m-%d")
day_nums = 1
current_dt = time.strftime("%Y-%m-%d", time.localtime())
current_dt = datetime.strptime(current_dt, '%Y-%m-%d')
previous_date = current_dt - timedelta(days=day_nums)
# data = jq.get_price(stock, end_date=previous_date, count=biasN +
# momentum_day, frequency='daily', fields=['close'])
try:
data = ak.stock_zh_a_daily(symbol=stock,start_date = from_date,end_date = previous_date)
except:
pass
#print('2222',data.head())
bias = np.array((data.close/data.close.rolling(biasN).mean())[-momentum_day:]) # 乖离因子
# print(bias)
# print(bias[0])
score = np.polyfit(np.arange(momentum_day), bias/bias[0], 1)[0].real # 乖离动量拟合
rank.append([stock, score])
rank.sort(key=lambda x: x[-1], reverse=True)
return rank[0]
# 线性回归:复现statsmodels的get_OLS函数
def get_ols(x, y):
slope, intercept = np.polyfit(x, y, 1)
r2 = 1 - (sum((y - (slope * x + intercept))**2) /((len(y) - 1) * np.var(y, ddof=1)))
return (intercept, slope, r2)
def get_zscore(slope_series):
mean = np.mean(slope_series)
std = np.std(slope_series)
return (slope_series[-1] - mean) / std
# 择时过程 ----->--------------------------------------------
def initial_slope_series():
current_dt = time.strftime("%Y-%m-%d", time.localtime())
current_dt = datetime.strptime(current_dt, '%Y-%m-%d')
from_date = '2010-01-01'
from_date = datetime.strptime(from_date,"%Y-%m-%d")
previous_date = current_dt - timedelta(days=day_nums)
data = ak.stock_zh_index_daily(symbol=ref_stock)
data['date'] =data['date'].apply(lambda x:str(x))
data['date'] = data['date'].apply(lambda x : datetime.strptime(str(x),'%Y-%m-%d'))
data = data[(data['date']>=from_date) & (data['date']<=previous_date)]
return [get_ols(data.low[i:i+N], data.high[i:i+N])[1] for i in range(M)]
# 只看RSRS因子值作为买入、持有和清仓依据,前版本还加入了移动均线的上行作为条件
def get_timing_signal(stock):
current_dt = time.strftime("%Y-%m-%d", time.localtime())
current_dt = datetime.strptime(current_dt, '%Y-%m-%d')
previous_date = current_dt - timedelta(days=day_nums)
from_date = '2010-01-01'
from_date = datetime.strptime(from_date,"%Y-%m-%d")
data = ak.stock_zh_index_daily(symbol=ref_stock)
data['date'] =data['date'].apply(lambda x:str(x))
data['date'] = data['date'].apply(lambda x : datetime.strptime(x,'%Y-%m-%d'))
data['date'] = data['date'].apply(lambda x : x.to_pydatetime())
#data = data[data['date']>=from_date & data['date']<= previous_date]
data = data[(data['date']>=from_date) & (data['date']<=previous_date)]
intercept, slope, r2 = get_ols(data.low, data.high)
slope_series.append(slope)
rsrs_score = get_zscore(slope_series[-M:]) * r2
print('rsrs_score {:.3f}'.format(rsrs_score))
if (rsrs_score > score_threshold):
return "BUY"
elif (rsrs_score < -score_threshold):
return "SELL"
else:
return "KEEP"
#slope_series = initial_slope_series()[:-1] # 除去回测第一天的 slope ,避免运行时重复加入
slope_series = initial_slope_series()[:-1]
def my_trade():
#print(stock_pool)
#print(get_rank(stock_pool))
check_out_list = get_rank(stock_pool)
timing_signal = get_timing_signal(ref_stock)
message = ""
if len(check_out_list) > 0:
each_check_out = check_out_list[0]
# security_info = jq.get_security_info(each_check_out)
# stock_name = security_info.display_name
# stock_code = each_check_out
print('今日自选股:{}({})'.format(each_check_out, each_check_out))
if timing_signal == 'SELL':
# for stock in list(positions.keys()):
# close_position(stock)
# message = '清仓!卖卖卖!'
# message += "\r\n\r\n".join(positions.keys())
# positions.clear()
# print('今日择时信号:{}'.format(timing_signal))
pass
else:
message = "今日自选股:{}({})".format(each_check_out, each_check_out)
#adjust_position([each_check_out])
print(message)
sendMail(message)
def mail(message):
ret = True
try:
current_dt = time.strftime("%Y-%m-%d", time.localtime())
# current_dt = datetime.strptime(current_dt, '%Y-%m-%d')
title = current_dt.split(" ")[0] + "投资操作"
msg = MIMEText(message,'plain','utf-8')
msg['From'] = formataddr(["**", my_sender]) # 发件人昵称
msg['To'] = formataddr(["**", my_user]) # 接收人昵称
msg['Subject'] = title # 邮件的主题
server = smtplib.SMTP_SSL("smtp.qq.com", 465) # 发件人邮箱中的SMTP服务器,端口是465
server.login(my_sender, my_pass) # 发件人邮箱账号、邮箱密码
server.sendmail(my_sender, [my_user,], msg.as_string()) # 发件人邮箱账号、收件人邮箱账号、发送邮件
server.quit() # 关闭连接
except Exception as e: # 如果 try 中的语句没有执行,则会执行下面的 ret = False
ret = False
print(e)
return ret
def sendMail(message):
ret = 0
for _ in range(10):
if ret:
# 邮件发送成功推出
break
else:
# 没有发送成功或失败继续
ret = mail(message)
time.sleep(1)
if __name__ == '__main__':
#positions["159928.XSHE"] = 100
my_trade()
The account password method of the mailbox is mentioned in my csdn, not your qq account password.