diff --git a/TurtleOnTime copy.py b/TurtleOnTime copy.py index a62d116..88abe86 100644 --- a/TurtleOnTime copy.py +++ b/TurtleOnTime copy.py @@ -5,12 +5,11 @@ import os from datetime import datetime, timedelta, date import pandas as pd import mplfinance as mpf -import sqlite3 -import stock_database import mysql_database from EmailTest import send_email, parse_return_email from dataclasses import dataclass import time +import threading ''' todo @@ -346,9 +345,10 @@ class TurtleTrading_OnTime(object): 3、实时监测主流程 ''' - def __init__(self, turtle: TurtleTrading, user_email): - self.turtle = turtle + def __init__(self, turtles: list[TurtleTrading], user_email): + self.turtles = turtles # List of TurtleTrading instances self.user_email = user_email + self.email_events = {} # Track email response events for each turtle def get_stocks_data(self): """获取实时股票、基金数据,不保存 @@ -717,18 +717,22 @@ class TurtleTrading_OnTime(object): # ------------------准备阶段-------------------- # 获取数据或读取数据 -- 计算ATR Donchian 20 50 up, 20 down - self.turtle.get_ready(100) - self.turtle.N = float(self.turtle.CurrentData['ATR'].iloc[-1]) - self.turtle.prev_heigh = float(self.turtle.CurrentData['最高价'].iloc[-1]) - self.turtle.Donchian_20_up = float(self.turtle.CurrentData['Donchian_20_upper'].iloc[-1]) - self.turtle.Donchian_50_up = float(self.turtle.CurrentData['Donchian_50_upper'].iloc[-1]) - self.turtle.Donchian_10_down = float(self.turtle.CurrentData['Donchian_10_lower'].iloc[-1]) - self.turtle.CalPositionSize() + # 初始化所有turtle + for turtle in self.turtles: + # 准备数据 + turtle.get_ready(100) + turtle.N = float(turtle.CurrentData['ATR'].iloc[-1]) + turtle.prev_heigh = float(turtle.CurrentData['最高价'].iloc[-1]) + turtle.Donchian_20_up = float(turtle.CurrentData['Donchian_20_upper'].iloc[-1]) + turtle.Donchian_50_up = float(turtle.CurrentData['Donchian_50_upper'].iloc[-1]) + turtle.Donchian_10_down = float(turtle.CurrentData['Donchian_10_lower'].iloc[-1]) + turtle.CalPositionSize() # ------------------实时监测阶段-------------------- # 9:00 1、判断是否是新的一周,是则重新计算Position Size # 判断是否是新的一周 if datetime.now().weekday() == 0: - self.turtle.CalPositionSize() + for turtle in self.turtles: + turtle.CalPositionSize() # 每分钟获取一次数据,判断是否触发条件 9:30-11:30 13:00-15:00 while True: @@ -757,8 +761,9 @@ class TurtleTrading_OnTime(object): break # 获取股票和ETF数据 - stock_data, etf_data = self.get_stocks_data() - self.run_short_trading_loop(stock_data, etf_data) + self.monitor_all_turtles() + # 等待一段时间后再次检查 + time.sleep(60) # 每分钟检查一次 # ------------------结束阶段-------------------- # 数据库更新当天数据,增加ATR、donchian数据 # 直接做个新表 @@ -766,6 +771,110 @@ class TurtleTrading_OnTime(object): self.turtle.get_ready(100) time.sleep(16.5*600) + + def monitor_all_turtles(self): + """主监控循环""" + # 获取实时数据 + stock_data, etf_data = self.get_stocks_data() + + # 遍历所有turtle进行监控 + for turtle in self.turtles: + self.monitor_single_turtle(turtle, stock_data, etf_data) + + + + def monitor_single_turtle(self, turtle: TurtleTrading, stock_data, etf_data): + """监控单个turtle的交易条件""" + + now = datetime.now().time() + if turtle.type == "stock": + turtle.PriceNow = float(stock_data.loc[etf_data['代码'] == self.turtle.TradeCode, '最新价'].values[0]) + + elif turtle.type == "etf": + # self.turtle.PriceNow = float(etf_data.loc[etf_data['基金代码'] == self.turtle.TradeCode, '当前-单位净值'].values[0]) + turtle.PriceNow = float(etf_data.loc[etf_data['代码'] == self.turtle.TradeCode, '最新价'].values[0]) + + if now.hour == 9 and now.minute == 30 and self.turtle.PriceNow > self.turtle.prev_heigh: + turtle.is_gap_up = True + + # 判断当前仓位状态并执行相应操作 + if turtle.TrigerTime == 0: + if turtle.system1EnterNormal( + turtle.PriceNow, + turtle.Donchian_20_up, + turtle.BreakOutLog + ): + + self.start_email_thread(turtle, "买入", turtle.PriceNow) + + # 突破 记录self.turtle.breakoutlog + today = datetime.now().strftime("%Y-%m-%d") + breakout_this_time = BreakOutLog(today, + turtle.Donchian_20_up, + turtle.Donchian_20_up - 2 * turtle.N, + 'valid', + None) + turtle.BreakOutLog.append(breakout_this_time) + + elif turtle.system1EnterSafe( + turtle.PriceNow, + turtle.Donchian_50_up + ): + self.start_email_thread(turtle, "买入", turtle.PriceNow) + + elif 1 <= turtle.TrigerTime <= 3: + + # 加仓状态 + if turtle.add(turtle.PriceNow): + self.start_email_thread(turtle, "加仓", turtle.PriceNow) + + # 止损状态 + elif turtle.system_1_stop(turtle.PriceNow): + self.start_email_thread(turtle, "止损", turtle.PriceNow) + + # 止盈 + elif turtle.system_1_Out( + turtle.PriceNow, + turtle.Donchian_10_down + ): + self.start_email_thread(turtle, "止盈", turtle.PriceNow) + + elif turtle.TrigerTime == 4: + # 满仓 止损 止盈 + if turtle.system_1_stop(turtle.PriceNow): + self.start_email_thread(turtle, "止损", turtle.PriceNow) + elif turtle.system_1_Out( + turtle.PriceNow, + turtle.Donchian_10_down + ): + self.start_email_thread(turtle, "止盈", turtle.PriceNow) + + def start_email_thread(self, turtle, action, price_now): + """启动邮件处理线程""" + event = threading.Event() + self.email_events[turtle.TradeCode] = event + + thread = threading.Thread( + target=self.handle_email_response, + args=(turtle, action, price_now, event) + ) + thread.start() + + def handle_email_response(self, turtle, action, price_now, event): + """处理邮件响应的线程""" + # 发送邮件 + if action == "买入": + self.Buy_stock(price_now) + elif action == "加仓": + self.add_stock(price_now) + elif action == "止损": + self.stop_sale_stock(price_now) + elif action == "止盈": + self.out_sale_stock(price_now) + + # 等待邮件响应 + event.wait() + if __name__ == '__main__': user_email = "guoyize2209@163.com" diff --git a/TurtleOnTime.py b/TurtleOnTime.py index 88abe86..418ae90 100644 --- a/TurtleOnTime.py +++ b/TurtleOnTime.py @@ -10,6 +10,7 @@ from EmailTest import send_email, parse_return_email from dataclasses import dataclass import time import threading +import yaml # 添加YAML支持 ''' todo @@ -90,6 +91,7 @@ class TurtleTrading(object): self.cash = cash self.TrigerTime = 0 self.BuyStates = list[BuyState] + self.state_file = f"state_{self.TradeCode}.yaml" # 状态文件名 self.tradeslog = list[TradeLog] self.BreakOutLog = list[BreakOutLog] @@ -335,7 +337,40 @@ class TurtleTrading(object): return False def day_end(self): - pass + self.save_state() # 每日结束保存状态 + + def save_state(self): + """保存当前状态到YAML文件""" + state_data = { + 'TrigerTime': self.TrigerTime, + 'BuyStates': [vars(bs) for bs in self.BuyStates], + 'tradeslog': [vars(tl) for tl in self.tradeslog], + 'BreakOutLog': [vars(bol) for bol in self.BreakOutLog], + 'PriceNow': self.PriceNow, + 'Donchian_20_up': self.Donchian_20_up, + 'Donchian_10_down': self.Donchian_10_down, + 'Donchian_50_up': self.Donchian_50_up, + 'is_gap_up': self.is_gap_up, + 'prev_heigh': self.prev_heigh + } + with open(self.state_file, 'w') as file: + yaml.dump(state_data, file) + + def load_state(self): + """从YAML文件加载状态""" + if os.path.exists(self.state_file): + with open(self.state_file, 'r') as file: + state_data = yaml.safe_load(file) + self.TrigerTime = state_data['TrigerTime'] + self.BuyStates = [BuyState(**bs) for bs in state_data['BuyStates']] + self.tradeslog = [TradeLog(**tl) for tl in state_data['tradeslog']] + self.BreakOutLog = [BreakOutLog(**bol) for bol in state_data['BreakOutLog']] + self.PriceNow = state_data['PriceNow'] + self.Donchian_20_up = state_data['Donchian_20_up'] + self.Donchian_10_down = state_data['Donchian_10_down'] + self.Donchian_50_up = state_data['Donchian_50_up'] + self.is_gap_up = state_data['is_gap_up'] + self.prev_heigh = state_data['prev_heigh'] class TurtleTrading_OnTime(object): ''' 实时监测主程序,可以处理多个turtle