247 lines
9.4 KiB
Python
247 lines
9.4 KiB
Python
|
import numpy as np
|
|||
|
import math
|
|||
|
import akshare as ak
|
|||
|
import os
|
|||
|
from datetime import datetime, timedelta, date
|
|||
|
import pandas as pd
|
|||
|
import mplfinance as mpf
|
|||
|
import sqlite3
|
|||
|
import stock_database
|
|||
|
import mysql_database
|
|||
|
|
|||
|
def calc_sma_atr_pd(kdf,period):
|
|||
|
"""计算TR与ATR
|
|||
|
|
|||
|
Args:
|
|||
|
kdf (_type_): 历史数据
|
|||
|
period (_type_): ATR周期
|
|||
|
|
|||
|
Returns:
|
|||
|
_type_: 返回kdf,增加TR与ATR列
|
|||
|
"""
|
|||
|
kdf['最高'] = kdf['最高'].astype(float)
|
|||
|
kdf['最低'] = kdf['最低'].astype(float)
|
|||
|
kdf['收盘'] = kdf['收盘'].astype(float)
|
|||
|
kdf['HL'] = kdf['最高'] - kdf['最低']
|
|||
|
kdf['HC'] = np.abs(kdf['最高'] - kdf['收盘'].shift(1))
|
|||
|
kdf['LC'] = np.abs(kdf['最低'] - kdf['收盘'].shift(1))
|
|||
|
kdf['TR'] = np.round(kdf[['HL','HC','LC']].max(axis=1), 3)
|
|||
|
# ranges = pd.concat([high_low, high_close, low_close], axis=1)
|
|||
|
# true_range = np.max(ranges, axis=1)
|
|||
|
kdf['ATR'] = np.round(kdf['TR'].rolling(period).mean(), 3)
|
|||
|
|
|||
|
return kdf.drop(['HL','HC','LC'], axis = 1)
|
|||
|
|
|||
|
class TurtleTrading(object):
|
|||
|
"""对象范围较小,对某一个标的创建一个海龟,如513300,
|
|||
|
计算ATR、唐奇安通道线
|
|||
|
基础数据
|
|||
|
Args:
|
|||
|
object (_type_): _description_
|
|||
|
"""
|
|||
|
def __init__(self, TradeCode) -> None:
|
|||
|
self.TradeCode = TradeCode
|
|||
|
|
|||
|
def GetRecentData(self):
|
|||
|
"""获取某个标的的最近数据,从两年前到今天, 计算后的数据保存在self.CurrentData
|
|||
|
|
|||
|
Returns:
|
|||
|
_type_: _description_
|
|||
|
"""
|
|||
|
Today = datetime.today()
|
|||
|
# print(Today)
|
|||
|
formatted_date = Today.strftime("%Y%m%d")
|
|||
|
two_years_ago = (date.today() - timedelta(days=365*2)).strftime("%Y%m%d")
|
|||
|
# print(formatted_date)
|
|||
|
Code = f"{self.TradeCode}"
|
|||
|
CurrentData = ak.fund_etf_hist_em(symbol=Code, period="daily", start_date=two_years_ago, end_date=formatted_date, adjust="")
|
|||
|
|
|||
|
# 将日期列转换为datetime
|
|||
|
CurrentData = pd.DataFrame(CurrentData)
|
|||
|
CurrentData['日期'] = pd.to_datetime(CurrentData['日期'])
|
|||
|
# print(type(CurrentData['日期'].iloc[0]))
|
|||
|
|
|||
|
CurrentData.set_index('日期', inplace=True)
|
|||
|
# CurrentData.reset_index(inplace=True)
|
|||
|
# print(type(CurrentData['日期'].iloc[0]))
|
|||
|
# create table
|
|||
|
# stock_database.create_table(Code)
|
|||
|
# stock_database.insert_data(Code, CurrentData)
|
|||
|
# mysql_database.insert_db(CurrentData, Code, True, "'日期'")
|
|||
|
self.CurrentData = CurrentData
|
|||
|
# return self.CurrentData
|
|||
|
|
|||
|
|
|||
|
def CalATR(self, data, ATRday):
|
|||
|
"""计算某个标的的ATR,从上市日到今天, 计算后的数据保存在self.CurrentData
|
|||
|
|
|||
|
Args:
|
|||
|
ATRday: 多少日ATR
|
|||
|
SaveOrNot (_type_): 是否保存.csv数据
|
|||
|
"""
|
|||
|
|
|||
|
self.CurrentData = calc_sma_atr_pd(data, ATRday)
|
|||
|
self.N = self.CurrentData['ATR']
|
|||
|
|
|||
|
|
|||
|
# return self.N
|
|||
|
|
|||
|
|
|||
|
def ReadExistData(self, data):
|
|||
|
"""除了通过发请求获取数据,也可以读本地的数据库,赋值给self.CurrentData
|
|||
|
|
|||
|
Args:
|
|||
|
data (_type_): 本地csv名称
|
|||
|
"""
|
|||
|
self.CurrentData = pd.read_csv(data)
|
|||
|
|
|||
|
def DrawKLine(self, days):
|
|||
|
"""画出k线图看看,画出最近days天的K线图
|
|||
|
"""
|
|||
|
|
|||
|
# 日期部分
|
|||
|
|
|||
|
# dates = pd.to_datetime(self.CurrentData['日期'][-days:])
|
|||
|
# # Klinedf['Data'] = pd.to_datetime(self.CurrentData['日期'])
|
|||
|
Klinedf = pd.DataFrame()
|
|||
|
# Klinedf.set_index = Klinedf['Data']
|
|||
|
|
|||
|
# 其他数据
|
|||
|
Klinedf['Date'] = self.CurrentData['日期'][-days:]
|
|||
|
Klinedf['Open'] = self.CurrentData['开盘'][-days:].astype(float)
|
|||
|
Klinedf['High'] = self.CurrentData['最高'][-days:].astype(float)
|
|||
|
Klinedf['Low'] = self.CurrentData['最低'][-days:].astype(float)
|
|||
|
Klinedf['Close'] = self.CurrentData['收盘'][-days:].astype(float)
|
|||
|
Klinedf['Volume'] = self.CurrentData['成交量'][-days:].astype(float)
|
|||
|
|
|||
|
Klinedf.set_index(pd.to_datetime(Klinedf['Date']), inplace=True)
|
|||
|
# 画图
|
|||
|
mpf.plot(Klinedf, type='candle', style='yahoo', volume=False, mav=(5,), addplot=[mpf.make_addplot(self.Donchian_up['Upper'][-days:]), mpf.make_addplot(self.Donchian_down['lower'][-days:])], title=f"{self.TradeCode} K线图")
|
|||
|
|
|||
|
def calculate_donchian_channel_up(self, n):
|
|||
|
"""
|
|||
|
计算n日唐奇安上通道
|
|||
|
|
|||
|
参数:
|
|||
|
self.CurrentData (DataFrame): 包含价格数据的Pandas DataFrame,包含"High"
|
|||
|
n (int): 时间周期
|
|||
|
|
|||
|
返回:self.Donchian
|
|||
|
DataFrame: 唐奇安通道的DataFrame,包含"Upper"
|
|||
|
"""
|
|||
|
Donchian = pd.DataFrame() # 创建一个空的DataFrame用于存储唐奇安通道数据
|
|||
|
# 计算最高价和最低价的N日移动平均线
|
|||
|
Donchian['Upper'] = self.CurrentData['最高'].rolling(n).max() # 使用rolling函数计算n日最高价的移动最大值
|
|||
|
|
|||
|
# # 计算中间线
|
|||
|
# Donchian['Middle'] = (self.Donchian['Upper'] + self.Donchian['Lower']) / 2 # 计算上通道和下通道的中间线,但此行代码被注释掉了
|
|||
|
|
|||
|
return Donchian # 返回包含唐奇安上通道的DataFrame
|
|||
|
|
|||
|
def calculate_donchian_channel_down(self, n):
|
|||
|
"""
|
|||
|
计算n日唐奇安上通道
|
|||
|
|
|||
|
参数:
|
|||
|
self.CurrentData (DataFrame): 包含价格数据的Pandas DataFrame,包含"High"
|
|||
|
n (int): 时间周期
|
|||
|
|
|||
|
返回:self.Donchian
|
|||
|
DataFrame: 唐奇安通道的DataFrame,包含"Upper"
|
|||
|
"""
|
|||
|
Donchian = pd.DataFrame()
|
|||
|
# 计算最高价和最低价的N日移动平均线
|
|||
|
Donchian['lower'] = self.CurrentData['最低'].rolling(n).min()
|
|||
|
|
|||
|
# # 计算中间线
|
|||
|
# Donchian['Middle'] = (self.Donchian['Upper'] + self.Donchian['Lower']) / 2
|
|||
|
|
|||
|
return Donchian
|
|||
|
|
|||
|
def get_ready(self, days):
|
|||
|
"""创建一个turtle对象,获取数据,计算ATR,计算唐奇安通道
|
|||
|
|
|||
|
Args:
|
|||
|
days (_type_): _description_
|
|||
|
n (_type_): _description_
|
|||
|
"""
|
|||
|
# 检查mysql数据库中是否存在该股票的数据 或者数据库最后一条的时间距离今天是否两天以上
|
|||
|
current_date = date.today()
|
|||
|
threshold_date = current_date - timedelta(days=2)
|
|||
|
last_update = mysql_database.check_db_table_last_date(f"{self.TradeCode}")
|
|||
|
|
|||
|
if not mysql_database.check_db_table(f"{self.TradeCode}") or last_update < threshold_date:
|
|||
|
# 如果不存在,则从akshare获取数据并保存到mysql数据库
|
|||
|
if mysql_database.check_db_table(f"{self.TradeCode}") and last_update < threshold_date:
|
|||
|
mysql_database.delete_table(f"{self.TradeCode}")
|
|||
|
|
|||
|
self.GetRecentData()
|
|||
|
else:
|
|||
|
# 如果存在,则从mysql数据库中读取数据
|
|||
|
self.CurrentData = mysql_database.fetch_all_data(f"{self.TradeCode}")
|
|||
|
|
|||
|
|
|||
|
# 计算ATR
|
|||
|
self.CalATR(self.CurrentData, 20)
|
|||
|
# 计算唐奇安通道
|
|||
|
self.Donchian_up = self.calculate_donchian_channel_up(20)
|
|||
|
self.Donchian_down = self.calculate_donchian_channel_down(10)
|
|||
|
# 画图
|
|||
|
# self.DrawKLine(days)
|
|||
|
|
|||
|
# 把self.N, self.Donchian_up, self.Donchian_down, 添加到self.CurrentData后面,保存到mysql数据库
|
|||
|
self.CurrentData = pd.concat([self.CurrentData, self.Donchian_up, self.Donchian_down], axis=1)
|
|||
|
|
|||
|
Code = f"{self.TradeCode}"
|
|||
|
mysql_database.insert_db(self.CurrentData, Code, True, "日期")
|
|||
|
|
|||
|
# 一天结束,计算ATR,计算唐奇安通道,追加到已有的mysql数据库中
|
|||
|
def day_end(self):
|
|||
|
pass
|
|||
|
|
|||
|
class TurtleTrading_OnTime(object):
|
|||
|
''' 实时监测主程序,可以处理多个turtle
|
|||
|
|
|||
|
1、获取实时大盘数据
|
|||
|
2、根据turtles的代码,比较是否触发条件
|
|||
|
3、实时监测主流程
|
|||
|
'''
|
|||
|
|
|||
|
def __init__(self):
|
|||
|
pass
|
|||
|
def get_stocks_data(self):
|
|||
|
"""获取实时股票、基金数据,不保存
|
|||
|
"""
|
|||
|
stock_zh_a_spot_df = ak.stock_zh_a_spot_em()
|
|||
|
stock_zh_a_spot_df = stock_zh_a_spot_df.dropna(subset=['最新价'])
|
|||
|
# # print(stock_zh_a_spot_df)
|
|||
|
# # stock_zh_a_spot_df第一列加上时间,精确到分钟
|
|||
|
# stock_zh_a_spot_df['时间'] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|||
|
# mysql_database.insert_db(stock_zh_a_spot_df, "stock_price", True, "代码")
|
|||
|
|
|||
|
# etf_data = ak.fund_etf_spot_em()
|
|||
|
etf_data = ak.fund_etf_spot_ths()
|
|||
|
etf_data = etf_data.dropna(subset=['当前-单位净值'])
|
|||
|
# etf_data['时间'] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|||
|
# mysql_database.insert_db(etf_data, "etf_price", True, "代码")
|
|||
|
|
|||
|
|
|||
|
if __name__ == '__main__':
|
|||
|
# t = TurtleTrading('513300')
|
|||
|
# t.get_ready(100)
|
|||
|
|
|||
|
a = TurtleTrading_OnTime()
|
|||
|
a.get_stocks_data()
|
|||
|
|
|||
|
# # 全是股票
|
|||
|
# stock_zh_a_spot_df = ak.stock_zh_a_spot_em()
|
|||
|
# # stock_zh_a_spot_df.to_csv("stock_zh_a_spot.txt", sep="\t", index=False, encoding="utf-8")
|
|||
|
# stock_zh_a_spot_df = stock_zh_a_spot_df.dropna(subset=['最新价'])
|
|||
|
# print(stock_zh_a_spot_df)
|
|||
|
|
|||
|
# # 全是基金
|
|||
|
# etf_data = ak.fund_etf_spot_em()
|
|||
|
# etf_data = etf_data.dropna(subset=['最新价'])
|
|||
|
# etf_data.to_csv("fund_etf_spot.txt", sep="\t", index=False, encoding="utf-8")
|
|||
|
# print(etf_data)
|
|||
|
|