''' #公众号:松鼠Quant #主页:www.quant789.com #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 该代码的主要目的是处理Tick数据并生成交易信号。代码中定义了一个tickcome函数,它接收到Tick数据后会进行一系列的处理,包括构建Tick字典、更新上一个Tick的成交量、保存Tick数据、生成K线数据等。其中涉及到的一些函数有: on_tick(tick): 处理单个Tick数据,根据Tick数据生成K线数据。 tickdata(df, symbol): 处理Tick数据,生成K线数据。 orderflow_df_new(df_tick, df_min, symbol): 处理Tick和K线数据,生成订单流数据。 GetOrderFlow_dj(kData): 计算订单流的信号指标。 除此之外,代码中还定义了一个MyTrader类,继承自TraderApiBase,用于实现交易相关的功能。 #公众号:松鼠Quant #主页:www.quant789.com #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 ''' from multiprocessing import Process, Queue from AlgoPlus.CTP.MdApi import run_tick_engine from AlgoPlus.CTP.FutureAccount import get_simulate_account from AlgoPlus.CTP.FutureAccount import FutureAccount from AlgoPlus.CTP.TraderApiBase import TraderApiBase from AlgoPlus.ta.time_bar import tick_to_bar import pandas as pd from datetime import datetime from datetime import time as s_time import operator import time import numpy as np import os import re import json import requests # 添加requests库用于API调用 from openai import OpenAI # 导入OpenAI客户端 import threading from queue import Queue as ThreadQueue import warnings warnings.filterwarnings("ignore", category=FutureWarning) # 在文件顶部定义全局变量 tickdatadict = {} # 存储Tick数据的字典 quotedict = {} # 存储行情数据的字典 ofdatadict = {} # 存储K线数据的字典 trader_df = pd.DataFrame({}) # 存储交易数据的DataFrame对象 previous_volume = {} # 上一个Tick的成交量 tsymbollist={} # 全局LLM配置变量 GLOBAL_LLM_CONFIG = {} # 全局大模型配置参数 # 全局交易信号队列,用于存储AI模型生成的交易信号 AI_SIGNAL_QUEUE = ThreadQueue() # 标记是否有AI线程正在运行 AI_THREAD_RUNNING = False # K线时间粒度 BAR_RESAMPLE_RULE = '1T' # 设置K线时间粒度,默认1分钟 def tickcome(md_queue): global previous_volume data=md_queue instrument_id = data['InstrumentID'].decode() # 品种代码 ActionDay = data['ActionDay'].decode() # 交易日日期 update_time = data['UpdateTime'].decode() # 更新时间 #zzg_quant update_millisec = str(data['UpdateMillisec']) # 更新毫秒数 created_at = ActionDay[:4] + '-' + ActionDay[4:6] + '-' + ActionDay[6:] + ' ' + update_time + '.' + update_millisec #创建时间 # 构建tick字典 tick = { 'symbol': instrument_id, # 品种代码和交易所ID 'created_at':datetime.strptime(created_at, "%Y-%m-%d %H:%M:%S.%f"), #'created_at': created_at, # 创建时间 'price': float(data['LastPrice']), # 最新价 'last_volume': int(data['Volume']) - previous_volume.get(instrument_id, 0) if previous_volume.get(instrument_id, 0) != 0 else 0, # 瞬时成交量 'bid_p': float(data['BidPrice1']), # 买价 'bid_v': int(data['BidVolume1']), # 买量 'ask_p': float(data['AskPrice1']), # 卖价 'ask_v': int(data['AskVolume1']), # 卖量 'UpperLimitPrice': float(data['UpperLimitPrice']), # 涨停价 'LowerLimitPrice': float(data['LowerLimitPrice']), # 跌停价 'TradingDay': data['TradingDay'].decode(), # 交易日日期 'cum_volume': int(data['Volume']), # 最新总成交量 'cum_amount': float(data['Turnover']), # 最新总成交额 'cum_position': int(data['OpenInterest']), # 合约持仓量 } # 更新上一个Tick的成交量 previous_volume[instrument_id] = int(data['Volume']) if tick['last_volume']>0: #print(tick['created_at'],'vol:',tick['last_volume']) # 处理Tick数据 on_tick(tick) def can_time(hour, minute): hour = str(hour) minute = str(minute) if len(minute) == 1: minute = "0" + minute return int(hour + minute) def on_tick(tick): tm=can_time(tick['created_at'].hour,tick['created_at'].minute) #print(tick['symbol']) #print(1) #if tm>1500 and tm<2100 : # return if tick['last_volume']==0: return quotes = tick timetick=str(tick['created_at']).replace('+08:00', '') tsymbol=tick['symbol'] if tsymbol not in tsymbollist.keys(): # 获取tick的买卖价和买卖量 #zzg_quant tsymbollist[tsymbol]=tick bid_p=quotes['bid_p'] ask_p=quotes['ask_p'] bid_v=quotes['bid_v'] ask_v=quotes['ask_v'] else: # 获取上一个tick的买卖价和买卖量 rquotes =tsymbollist[tsymbol] bid_p=rquotes['bid_p'] ask_p=rquotes['ask_p'] bid_v=rquotes['bid_v'] ask_v=rquotes['ask_v'] tsymbollist[tsymbol]=tick tick_dt=pd.DataFrame({'datetime':timetick,'symbol':tick['symbol'],'mainsym':tick['symbol'].rstrip('0123456789').upper(),'lastprice':tick['price'], 'vol':tick['last_volume'], 'bid_p':bid_p,'ask_p':ask_p,'bid_v':bid_v,'ask_v':ask_v},index=[0]) sym = tick_dt['symbol'][0] #print(tick_dt) tickdata(tick_dt,sym) #公众号:松鼠Quant #主页:www.quant789.com #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 def data_of(df): global trader_df # 将df数据合并到trader_df中 trader_df = pd.concat([trader_df, df], ignore_index=True) #print('trader_df: ', len(trader_df)) #print(trader_df) def process(bidDict, askDict, symbol): try: # 尝试从quotedict中获取对应品种的报价数据 dic = quotedict[symbol] bidDictResult = dic['bidDictResult'] askDictResult = dic['askDictResult'] except: # 如果获取失败,则初始化bidDictResult和askDictResult为空字典 bidDictResult, askDictResult = {}, {} # 将所有买盘字典和卖盘字典的key合并,并按升序排序 sList = sorted(set(list(bidDict.keys()) + list(askDict.keys()))) # 遍历所有的key,将相同key的值进行累加 for s in sList: if s in bidDict: if s in bidDictResult: bidDictResult[s] = int(bidDict[s]) + bidDictResult[s] else: bidDictResult[s] = int(bidDict[s]) if s not in askDictResult: askDictResult[s] = 0 else: if s in askDictResult: askDictResult[s] = int(askDict[s]) + askDictResult[s] else: askDictResult[s] = int(askDict[s]) if s not in bidDictResult: bidDictResult[s] = 0 # 构建包含bidDictResult和askDictResult的字典,并存入quotedict中 df = {'bidDictResult': bidDictResult, 'askDictResult': askDictResult} quotedict[symbol] = df return bidDictResult, askDictResult #公众号:松鼠Quant #主页:www.quant789.com #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 def tickdata(df,symbol): tickdata =pd.DataFrame({'datetime':df['datetime'],'symbol':df['symbol'],'lastprice':df['lastprice'], 'volume':df['vol'],'bid_p':df['bid_p'],'bid_v':df['bid_v'],'ask_p':df['ask_p'],'ask_v':df['ask_v']}) try: if symbol in tickdatadict.keys(): rdf=tickdatadict[symbol] rdftm=pd.to_datetime(rdf['bartime'][0]).strftime('%Y-%m-%d %H:%M:%S') now=str(tickdata['datetime'][0]) if now>rdftm: try: oo=ofdatadict[symbol] data_of(oo) #print('oo',oo) if symbol in quotedict.keys(): quotedict.pop(symbol) if symbol in tickdatadict.keys(): tickdatadict.pop(symbol) if symbol in ofdatadict.keys(): ofdatadict.pop(symbol) except IOError as e: print('rdftm捕获到异常',e) tickdata['bartime'] = pd.to_datetime(tickdata['datetime']) tickdata['open'] = tickdata['lastprice'] tickdata['high'] = tickdata['lastprice'] tickdata['low'] = tickdata['lastprice'] tickdata['close'] = tickdata['lastprice'] tickdata['starttime'] = tickdata['datetime'] else: tickdata['bartime'] = rdf['bartime'] tickdata['open'] = rdf['open'] tickdata['high'] = max(tickdata['lastprice'].values,rdf['high'].values) tickdata['low'] = min(tickdata['lastprice'].values,rdf['low'].values) tickdata['close'] = tickdata['lastprice'] tickdata['volume']=df['vol']+rdf['volume'].values tickdata['starttime'] = rdf['starttime'] else : print('新bar的第一个tick进入') tickdata['bartime'] = pd.to_datetime(tickdata['datetime']) tickdata['open'] = tickdata['lastprice'] tickdata['high'] = tickdata['lastprice'] tickdata['low'] = tickdata['lastprice'] tickdata['close'] = tickdata['lastprice'] tickdata['starttime'] = tickdata['datetime'] except IOError as e: print('捕获到异常',e) tickdata['bartime'] = pd.to_datetime(tickdata['bartime']) bardata = tickdata.resample(on = 'bartime', rule = BAR_RESAMPLE_RULE, label = 'right', closed = 'right').agg({'starttime':'first','symbol':'last','open':'first','high':'max','low':'min','close':'last','volume':'sum'}).reset_index(drop = False) bardata =bardata.dropna().reset_index(drop = True) bardata['bartime'] = pd.to_datetime(bardata['bartime'][0]).strftime('%Y-%m-%d %H:%M:%S') tickdatadict[symbol]=bardata tickdata['volume']=df['vol'].values #print(bardata['symbol'].values,bardata['bartime'].values) orderflow_df_new(tickdata,bardata,symbol) # time.sleep(0.5) #公众号:松鼠Quant #主页:www.quant789.com #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 def orderflow_df_new(df_tick,df_min,symbol): startArray = pd.to_datetime(df_min['starttime']).values voluememin= df_min['volume'].values highs=df_min['high'].values lows=df_min['low'].values opens=df_min['open'].values closes=df_min['close'].values #endArray = pd.to_datetime(df_min['bartime']).values endArray = df_min['bartime'].values #print(endArray) deltaArray = np.zeros((len(endArray),)) tTickArray = pd.to_datetime(df_tick['datetime']).values bp1TickArray = df_tick['bid_p'].values ap1TickArray = df_tick['ask_p'].values lastTickArray = df_tick['lastprice'].values volumeTickArray = df_tick['volume'].values symbolarray = df_tick['symbol'].values indexFinal = 0 for index,tEnd in enumerate(endArray): dt=endArray[index] start = startArray[index] bidDict = {} askDict = {} bar_vol=voluememin[index] bar_close=closes[index] bar_open=opens[index] bar_low=lows[index] bar_high=highs[index] bar_symbol=symbolarray[index] # for indexTick in range(indexFinal,len(df_tick)): # if tTickArray[indexTick] >= tEnd: # break # elif (tTickArray[indexTick] >= start) & (tTickArray[indexTick] < tEnd): Bp = round(bp1TickArray[0],4) Ap = round(ap1TickArray[0],4) LastPrice = round(lastTickArray[0],4) Volume = volumeTickArray[0] if LastPrice >= Ap: if str(LastPrice) in askDict.keys(): askDict[str(LastPrice)] += Volume else: askDict[str(LastPrice)] = Volume if LastPrice <= Bp: if str(LastPrice) in bidDict.keys(): bidDict[str(LastPrice)] += Volume else: bidDict[str(LastPrice)] = Volume # indexFinal = indexTick bidDictResult,askDictResult = process(bidDict,askDict,symbol) bidDictResult=dict(sorted(bidDictResult.items(),key=operator.itemgetter(0))) askDictResult=dict(sorted(askDictResult.items(),key=operator.itemgetter(0))) prinslist=list(bidDictResult.keys()) asklist=list(askDictResult.values()) bidlist=list(bidDictResult.values()) delta=(sum(askDictResult.values()) - sum(bidDictResult.values())) #print(prinslist,asklist,bidlist) #print(len(prinslist),len(bidDictResult),len(askDictResult)) df=pd.DataFrame({'price':pd.Series([prinslist]),'Ask':pd.Series([asklist]),'Bid':pd.Series([bidlist])}) #df=pd.DataFrame({'price':pd.Series(bidDictResult.keys()),'Ask':pd.Series(askDictResult.values()),'Bid':pd.Series(bidDictResult.values())}) df['symbol']=bar_symbol df['datetime']=dt df['delta']=str(delta) df['close']=bar_close df['open']=bar_open df['high']=bar_high df['low']=bar_low df['volume']=bar_vol #df['ticktime']=tTickArray[0] df['dj'] = GetOrderFlow_dj(df) ofdatadict[symbol]=df #公众号:松鼠Quant #主页:www.quant789.com #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 def GetOrderFlow_dj(kData): Config = { 'Value1': 3, 'Value2': 3, 'Value3': 3, 'Value4': True, } aryData = kData djcout = 0 # 遍历kData中的每一行,计算djcout指标 for index, row in aryData.iterrows(): kItem = aryData.iloc[index] high = kItem['high'] low = kItem['low'] close = kItem['close'] open = kItem['open'] dtime = kItem['datetime'] price_s = kItem['price'] Ask_s = kItem['Ask'] Bid_s = kItem['Bid'] delta = kItem['delta'] price_s = price_s Ask_s = Ask_s Bid_s = Bid_s gj = 0 xq = 0 gxx = 0 xxx = 0 # 遍历price_s中的每一个元素,计算相关指标 for i in np.arange(0, len(price_s), 1): duiji = { 'price': 0, 'time': 0, 'longshort': 0, } if i == 0: delta = delta order= { "Price":price_s[i], "Bid":{ "Value":Bid_s[i]}, "Ask":{ "Value":Ask_s[i]} } #空头堆积 if i >= 0 and i < len(price_s) - 1: if (order["Bid"]["Value"] > Ask_s[i + 1] * int(Config['Value1'])): gxx += 1 gj += 1 if gj >= int(Config['Value2']) and Config['Value4'] == True: duiji['price'] = price_s[i] duiji['time'] = dtime duiji['longshort'] = -1 if float(duiji['price']) > 0: djcout += -1 else: gj = 0 #多头堆积 if i >= 1 and i <= len(price_s) - 1: if (order["Ask"]["Value"] > Bid_s[i - 1] * int(Config['Value1'])): xq += 1 xxx += 1 if xq >= int(Config['Value2']) and Config['Value4'] == True: duiji['price'] = price_s[i] duiji['time'] = dtime duiji['longshort'] = 1 if float(duiji['price']) > 0: djcout += 1 else: xq = 0 # 返回计算得到的djcout值 return djcout #交易程序--------------------------------------------------------------------------------------------------------------------------------------------------------------------- class MyTrader(TraderApiBase): def __init__(self, broker_id, td_server, investor_id, password, app_id, auth_code, md_queue=None, page_dir='', private_resume_type=2, public_resume_type=2): # Cython类不使用super().__init__()方式调用父类初始化方法 # TraderApiBase.__init__会由Cython自动处理 self.py=30 #设置委托价格的偏移,更加容易促成成交。仅螺纹,其他品种根据最小点波动,自己设置 self.cont_df=0 self.trailing_stop_percent = 0.005 #跟踪出场参数,从0.02减小到0.005 self.fixed_stop_loss_percent = 0.01 #固定出场参数 self.dj_X=1 #开仓的堆积参数 self.pos=0 self.Lots=1 #下单手数 self.short_trailing_stop_price = 0 self.long_trailing_stop_price = 0 self.sl_long_price=0 self.sl_shor_price=0 self.out_long=0 self.out_short=0 self.clearing_executed=False self.day_closed = False # 添加日内平仓标志 self.kgdata = True #历史数据加载一次 self.holddata=True #持仓数据加载一次 self.use_ai_model = True # 是否使用AI模型来分析 # 新增止盈止损字典,按合约ID索引 self.stop_order_dict = {} # 新增历史数据加载相关参数 self.load_history = False # 是否加载历史数据 self.history_rows = 30 # 默认加载30行历史数据 self.trader_rows = 10 # 当tader_df里的数据大于10行时开始计算指标及触发AI模型 def load_history_data(self, instrument_id): """ 加载历史数据 Args: instrument_id: 合约ID """ if not self.load_history: return try: # 不再只提取英文字母,使用完整的合约代码 symbol = str(instrument_id) json_file_path = f"traderdata/{symbol}_ofdata.json" # 检查traderdata目录是否存在 if not os.path.exists("traderdata"): print(f"traderdata目录不存在,创建目录") os.makedirs("traderdata") if os.path.exists(json_file_path): try: # 读取JSON文件,使用lines=True确保正确读取每行JSON df = pd.read_json(json_file_path, lines=True) if len(df) == 0: print(f"历史数据文件为空: {json_file_path}") print("将使用实时数据开始交易") return False # 如果数据行数超过设定的历史行数,只取最后N行 if len(df) > self.history_rows: df = df.tail(self.history_rows) print(f"历史数据超过设定行数,仅加载最后{self.history_rows}行") # 更新全局trader_df global trader_df trader_df = df print(f"\n===== 历史数据加载成功 =====") print(f"合约: {instrument_id}") print(f"数据行数: {len(df)}行") print(f"数据时间范围: {df['datetime'].iloc[0]} 到 {df['datetime'].iloc[-1]}") print(f"最新价格: {df['close'].iloc[-1]}") print(f"最新成交量: {df['volume'].iloc[-1]}") print("===========================\n") # 更新cont_df self.cont_df = len(df) # 计算日均线 if len(df) > 0: df['dayma'] = df['close'].mean() # 计算累积的delta值 df['delta'] = df['delta'].astype(float) df['delta累计'] = df['delta'].cumsum() return True except Exception as e: print(f"\n===== 历史数据加载错误 =====") print(f"合约: {instrument_id}") print(f"读取JSON错误: {e}") print("将使用实时数据开始交易") print("===========================\n") return False else: print(f"\n===== 历史数据加载提示 =====") print(f"合约: {instrument_id}") print(f"未找到历史数据文件: {json_file_path}") print("将使用实时数据开始交易") print("===========================\n") return False except Exception as e: print(f"\n===== 历史数据加载错误 =====") print(f"合约: {instrument_id}") print(f"错误信息: {e}") print("将使用实时数据开始交易") print("===========================\n") return False #读取保存的数据 def read_to_csv(self,symbol): # 文件夹路径和文件路径 # 使用完整的合约代码 symbol = str(symbol) folder_path = "traderdata" file_path = os.path.join(folder_path, f"{symbol}traderdata.csv") # 如果文件夹不存在则创建 if not os.path.exists(folder_path): os.makedirs(folder_path) # 读取保留的模型数据CSV文件 if os.path.exists(file_path): df = pd.read_csv(file_path) if not df.empty and self.holddata==True: # 选择最后一行数据 row = df.iloc[-1] # 根据CSV文件的列名将数据赋值给相应的属性 self.pos = int(row['pos']) self.short_trailing_stop_price = float(row['short_trailing_stop_price']) self.long_trailing_stop_price = float(row['long_trailing_stop_price']) self.sl_long_price = float(row['sl_long_price']) self.sl_shor_price = float(row['sl_shor_price']) # self.out_long = int(row['out_long']) # self.out_short = int(row['out_short']) print("找到历史交易数据文件,已经更新持仓,止损止盈数据", df.iloc[-1]) self.holddata=False else: pass #print("没有找到历史交易数据文件", file_path) #如果没有找到CSV,则初始化变量 pass #保存数据 def save_to_csv(self,symbol): # 使用完整的合约代码 symbol = str(symbol) # 创建DataFrame data = { 'datetime': [datetime.now().strftime('%Y-%m-%d %H:%M:%S')], # 使用当前时间 'pos': [self.pos], 'short_trailing_stop_price': [self.short_trailing_stop_price], 'long_trailing_stop_price': [self.long_trailing_stop_price], 'sl_long_price': [self.sl_long_price], 'sl_shor_price': [self.sl_shor_price], } df = pd.DataFrame(data) # 将DataFrame保存到CSV文件 df.to_csv(f"traderdata/{symbol}traderdata.csv", index=False) #每日收盘重置数据 def day_data_reset(self,data): # 获取当前时间 current_time = datetime.now().time() # 第一时间范围 clearing_time1_start = s_time(14,55) clearing_time1_end = s_time(15,00) # 第二时间范围 clearing_time2_start = s_time(2,25) clearing_time2_end = s_time(2,30) current_bid = float(data['BidPrice1']) # 当前买价 current_ask = float(data['AskPrice1']) # 当前卖价 # 创建一个标志变量,用于记录是否已经执行过 self.clearing_executed = False # 检查当前时间第一个操作的时间范围内 if clearing_time1_start <= current_time <= clearing_time1_end and not self.clearing_executed : self.clearing_executed = True # 设置标志变量为已执行 # 如果有持仓,强制平仓 if self.pos != 0: print("交易日结束,开始强制平仓") # 遍历所有合约发送平仓指令 for instrument_id in list(self.stop_order_dict.keys()): stops = self.stop_order_dict[instrument_id] # 平多仓 if stops['long']['position'] > 0: print(f"发送平多仓指令: {instrument_id}, 手数: {stops['long']['position']}, 价格: {current_bid}") self.insert_order(data['ExchangeID'], data['InstrumentID'], current_bid - self.py, stops['long']['position'], b'1', b'3') # 平空仓 if stops['short']['position'] > 0: print(f"发送平空仓指令: {instrument_id}, 手数: {stops['short']['position']}, 价格: {current_ask}") self.insert_order(data['ExchangeID'], data['InstrumentID'], current_ask + self.py, stops['short']['position'], b'0', b'3') # 清空所有合约的持仓信息 for instrument_id in list(self.stop_order_dict.keys()): self.clear_position_info(instrument_id, 'all') self.day_closed = True # 设置日内平仓标志 print("日内交易已结束,禁止开新仓") # 检查当前时间是否在第二个操作的时间范围内 elif clearing_time2_start <= current_time <= clearing_time2_end and not self.clearing_executed : self.clearing_executed = True # 设置标志变量为已执行 # 如果有持仓,强制平仓 if self.pos != 0: print("交易日结束,开始强制平仓") # 遍历所有合约发送平仓指令 for instrument_id in list(self.stop_order_dict.keys()): stops = self.stop_order_dict[instrument_id] # 平多仓 if stops['long']['position'] > 0: print(f"发送平多仓指令: {instrument_id}, 手数: {stops['long']['position']}, 价格: {current_bid}") self.insert_order(data['ExchangeID'], data['InstrumentID'], current_bid - self.py, stops['long']['position'], b'1', b'3') # 平空仓 if stops['short']['position'] > 0: print(f"发送平空仓指令: {instrument_id}, 手数: {stops['short']['position']}, 价格: {current_ask}") self.insert_order(data['ExchangeID'], data['InstrumentID'], current_ask + self.py, stops['short']['position'], b'0', b'3') # 清空所有合约的持仓信息 for instrument_id in list(self.stop_order_dict.keys()): self.clear_position_info(instrument_id, 'all') self.day_closed = True # 设置日内平仓标志 print("日内交易已结束,禁止开新仓") else: self.clearing_executed = False # 在新交易日开始时重置日内平仓标志 if current_time < clearing_time1_start or (current_time > clearing_time1_end and current_time < clearing_time2_start): self.day_closed = False return self.clearing_executed def OnRtnTrade(self, pTrade): print("||成交回报||", pTrade) # 获取成交信息 instrument_id = pTrade['InstrumentID'].decode() direction = pTrade['Direction'].decode() # '0'为买入,'1'为卖出 offset_flag = pTrade['OffsetFlag'].decode() # '0'为开仓,'1'为平仓,'3'为平今 volume = pTrade['Volume'] price = pTrade['Price'] # 根据成交类型更新持仓信息 if offset_flag in ['1', '3']: # 平仓或平今 # 判断平的是多头还是空头 if direction == '1': # 卖出,平多头 print(f"平多头成交: {instrument_id}, 价格: {price}, 数量: {volume}") # 清空多头持仓信息 self.clear_position_info(instrument_id, 'long') else: # 买入,平空头 print(f"平空头成交: {instrument_id}, 价格: {price}, 数量: {volume}") # 清空空头持仓信息 self.clear_position_info(instrument_id, 'short') elif offset_flag == '0': # 开仓 if direction == '0': # 买入,开多头 print(f"开多头成交: {instrument_id}, 价格: {price}, 数量: {volume}") # 如果有空头持仓,先清空 if instrument_id in self.stop_order_dict and self.stop_order_dict[instrument_id]['short']['position'] > 0: self.clear_position_info(instrument_id, 'short') # 设置多头持仓信息 sl_price = price * (1 - self.fixed_stop_loss_percent) # 默认止损价 tp_price = price * (1 + self.trailing_stop_percent) # 默认止盈价 # 设置初始跟踪止损价,与开仓价保持一定距离 initial_trailing_stop = price * (1 - self.trailing_stop_percent) print(f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%") # 更新多头持仓信息,设置合理的跟踪止损初始值 self.update_stop_order_dict(instrument_id, 'long', volume, price, sl_price, tp_price, initial_trailing_stop) self.pos = volume # 更新全局持仓状态 # 兼容旧代码 self.long_trailing_stop_price = initial_trailing_stop self.sl_long_price = sl_price self.save_to_csv(instrument_id) else: # 卖出,开空头 print(f"开空头成交: {instrument_id}, 价格: {price}, 数量: {volume}") # 如果有多头持仓,先清空 if instrument_id in self.stop_order_dict and self.stop_order_dict[instrument_id]['long']['position'] > 0: self.clear_position_info(instrument_id, 'long') # 设置空头持仓信息 sl_price = price * (1 + self.fixed_stop_loss_percent) # 默认止损价 tp_price = price * (1 - self.trailing_stop_percent) # 默认止盈价 # 设置初始跟踪止损价,与开仓价保持一定距离 initial_trailing_stop = price * (1 + self.trailing_stop_percent) print(f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%") # 更新空头持仓信息,设置合理的跟踪止损初始值 self.update_stop_order_dict(instrument_id, 'short', self.Lots, price, sl_price, tp_price, initial_trailing_stop) self.pos = -1 # 更新全局持仓状态 # 兼容旧代码 self.short_trailing_stop_price = initial_trailing_stop self.sl_shor_price = sl_price self.save_to_csv(instrument_id) def OnRspOrderInsert(self, pInputOrder, pRspInfo, nRequestID, bIsLast): print("||OnRspOrderInsert||", pInputOrder, pRspInfo, nRequestID, bIsLast) #公众号:松鼠Quant #主页:www.quant789.com #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 #注意:运行前请先安装好algoplus, # pip install AlgoPlus #http://www.algo.plus/ctp/python/0103001.html # 订单状态通知 def OnRtnOrder(self, pOrder): print("||订单回报||", pOrder) def Join(self): data = None # 记录上次加载止盈止损信息的时间和合约 last_load_time = {} while True: if self.status == 0: while not self.md_queue.empty(): data = self.md_queue.get(block=False) instrument_id = data['InstrumentID'].decode() # 品种代码 # 首次运行时加载历史数据 if self.kgdata: self.load_history_data(instrument_id) self.kgdata = False # 加载该合约的止盈止损信息,避免频繁加载 current_time = time.time() if instrument_id not in last_load_time or current_time - last_load_time.get(instrument_id, 0) > 60: # 每60秒才重新加载一次 self.load_stop_orders_from_file(instrument_id) last_load_time[instrument_id] = current_time # 检查止盈止损条件 self.check_stop_conditions(data) # 在每个tick都检查和处理AI交易信号 - 移到这里以提高执行速度 if self.use_ai_model: self.check_and_process_ai_signals(data) # 原有代码... self.read_to_csv(instrument_id) self.day_data_reset(data) tickcome(data) #新K线开始,启动交易程序 and 保存行情数据 if len(trader_df)>self.cont_df and len(trader_df)>0: # 计算日均线 trader_df['dayma'] = trader_df['close'].mean() # 计算累积的delta值 trader_df['delta'] = trader_df['delta'].astype(float) trader_df['delta累计'] = trader_df['delta'].cumsum() # 检查文件是否存在 json_file_path = f"traderdata/{instrument_id}_ofdata.json" if os.path.exists(json_file_path): try: # 读取现有数据 existing_df = pd.read_json(json_file_path, lines=True) # 合并新数据 combined_df = pd.concat([existing_df, trader_df.tail(1)], ignore_index=True) # 保存合并后的数据,使用lines=True确保每行是独立的JSON对象 combined_df.to_json(json_file_path, orient='records', force_ascii=False, lines=True) except Exception as e: print(f"读取或保存JSON文件时出错: {e}") # 如果读取出错,直接保存当前数据 trader_df.to_json(json_file_path, orient='records', force_ascii=False, lines=True) else: # 创建新文件并保存整个DataFrame trader_df.to_json(json_file_path, orient='records', force_ascii=False, lines=True) # 更新跟踪止损价格 - 兼容旧版本代码 if self.long_trailing_stop_price >0 and self.pos>0: self.long_trailing_stop_price = trader_df['low'].iloc[-1] if self.long_trailing_stop_price0 and self.pos<0: self.short_trailing_stop_price = trader_df['high'].iloc[-1] if trader_df['high'].iloc[-1] self.trader_rows: AI_THREAD_RUNNING = True ai_thread = threading.Thread( target=self.background_model_call, args=(trader_df, instrument_id) ) ai_thread.daemon = True # 设置为守护线程,主程序退出时自动结束 ai_thread.start() print("启动AI分析线程...") print(trader_df) self.cont_df=len(trader_df) else: time.sleep(1) def background_model_call(self, data_df, instrument_id): """ 在后台线程中调用大模型,并将交易信号放入队列 Args: data_df: 包含订单流数据的DataFrame instrument_id: 合约ID """ global AI_THREAD_RUNNING start_time = datetime.now() print(f"\n===== 开始AI分析 [{start_time.strftime('%H:%M:%S')}] =====") print(f"正在分析合约: {instrument_id}") try: # 复制DataFrame以避免在不同线程间共享数据可能导致的问题 df_copy = data_df.copy() # 输出分析的数据行数 print(f"分析数据行数: {len(df_copy)}") print(f"最新价格: {df_copy['close'].iloc[-1] if len(df_copy) > 0 else 'N/A'}") # 调用大模型获取交易信号 trading_signal = call_deepseek_model(df_copy, self) # 传递self参数 # 计算分析耗时 end_time = datetime.now() elapsed = (end_time - start_time).total_seconds() # 将交易信号和合约ID一起放入队列 signal_data = { 'signal': trading_signal, 'instrument_id': instrument_id, 'timestamp': end_time # 使用结束时间作为时间戳 } AI_SIGNAL_QUEUE.put(signal_data) print(f"AI模型分析完成,结果已放入队列,耗时: {elapsed:.2f}秒") print(f"分析结果: {trading_signal}") print("===== AI分析完成 =====\n") except Exception as e: end_time = datetime.now() elapsed = (end_time - start_time).total_seconds() print(f"AI模型分析线程出现异常: {e}") print(f"异常详情:") import traceback traceback.print_exc() print(f"分析失败,耗时: {elapsed:.2f}秒") print("===== AI分析异常结束 =====\n") finally: # 标记线程已完成 AI_THREAD_RUNNING = False #公众号:松鼠Quant #主页:www.quant789.com #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 #注意:运行前请先安装好algoplus, # pip install AlgoPlus #http://www.algo.plus/ctp/python/0103001.html def check_and_process_ai_signals(self, data): """ 检查并处理AI产生的交易信号 每个tick都会调用此函数,实现更快的交易信号响应 """ if AI_SIGNAL_QUEUE.empty(): return # 从队列中获取信号 signal_data = AI_SIGNAL_QUEUE.get() trading_signal = signal_data['signal'] instrument_id = signal_data['instrument_id'] signal_time = signal_data['timestamp'] # 检查信号是否过期(超过15秒) if (datetime.now() - signal_time).total_seconds() > 15: print(f"AI信号已过期,忽略: {trading_signal}") return # 验证合约ID是否匹配 if instrument_id != data['InstrumentID'].decode(): # 如果合约不匹配,将信号放回队列以便后续处理 AI_SIGNAL_QUEUE.put(signal_data) return print(f"\n===== 执行AI模型交易信号 [{datetime.now().strftime('%H:%M:%S')}] =====") print(f"信号生成时间: {signal_time.strftime('%H:%M:%S')}") print(f"信号类型: {trading_signal.get('action', '不操作')}") print(f"置信度: {trading_signal.get('confidence', 0)}") print(f"理由: {trading_signal.get('reason', '')}") # 根据AI模型返回的交易信号执行交易 action = trading_signal.get('action', '不操作') confidence = trading_signal.get('confidence', 0) reason = trading_signal.get('reason', '') stop_loss = trading_signal.get('stop_loss', 0) take_profit = trading_signal.get('take_profit', 0) trailing_percent = trading_signal.get('trailing_percent', 0) # 如果AI建议了有效的跟踪止损百分比,则更新参数 if 0.0001 <= trailing_percent <= 0.001: old_percent = self.trailing_stop_percent self.trailing_stop_percent = trailing_percent print(f"更新跟踪止损百分比参数: {old_percent*100:.3f}% -> {trailing_percent*100:.3f}%") # 获取现有持仓信息 if instrument_id not in self.stop_order_dict: self.stop_order_dict[instrument_id] = { 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} } current_stops = self.stop_order_dict[instrument_id] # 如果持有多头或空头头寸,更新跟踪止损价 if current_stops['long']['position'] > 0: entry_price = current_stops['long']['entry_price'] new_trailing_stop = float(data['BidPrice1']) * (1 - self.trailing_stop_percent) old_trailing_stop = current_stops['long']['trailing_stop'] # 只有当新计算的跟踪止损价更高时才更新 if new_trailing_stop > old_trailing_stop: self.update_stop_order_dict(instrument_id, 'long', None, None, None, None, new_trailing_stop) print(f"已根据新参数更新多头跟踪止损价: {old_trailing_stop} -> {new_trailing_stop}") # 兼容旧代码 self.long_trailing_stop_price = new_trailing_stop self.save_to_csv(instrument_id) elif current_stops['short']['position'] > 0: entry_price = current_stops['short']['entry_price'] new_trailing_stop = float(data['AskPrice1']) * (1 + self.trailing_stop_percent) old_trailing_stop = current_stops['short']['trailing_stop'] # 只有当新计算的跟踪止损价更低时才更新 if new_trailing_stop < old_trailing_stop or old_trailing_stop == 0: self.update_stop_order_dict(instrument_id, 'short', None, None, None, None, new_trailing_stop) print(f"已根据新参数更新空头跟踪止损价: {old_trailing_stop} -> {new_trailing_stop}") # 兼容旧代码 self.short_trailing_stop_price = new_trailing_stop self.save_to_csv(instrument_id) # 只有当置信度大于等于5时才执行交易 if confidence >= 6: print(f"开始执行交易,当前价格: 买一{data['BidPrice1']} / 卖一{data['AskPrice1']}") # 获取现有持仓信息 if instrument_id not in self.stop_order_dict: self.stop_order_dict[instrument_id] = { 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} } current_stops = self.stop_order_dict[instrument_id] if action == '开多' and current_stops['long']['position'] <= 0: # 如果持有空头头寸,先平空 if current_stops['short']['position'] > 0: print('执行平空操作') self.insert_order(data['ExchangeID'], data['InstrumentID'], data['AskPrice1']+self.py, current_stops['short']['position'], b'0', b'3') # 清空空头持仓信息 self.clear_position_info(instrument_id, 'short') # 开多 print('执行开多操作') entry_price = float(data['AskPrice1']) self.insert_order(data['ExchangeID'], data['InstrumentID'], entry_price+self.py, self.Lots, b'0', b'0') # 使用AI建议的止损止盈价格 sl_price = stop_loss if stop_loss > 0 else entry_price * (1 - self.fixed_stop_loss_percent) tp_price = take_profit if take_profit > 0 else entry_price * (1 + self.trailing_stop_percent) # 设置初始跟踪止损价,与开仓价保持一定距离 initial_trailing_stop = entry_price * (1 - self.trailing_stop_percent) print(f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%") # 更新多头持仓信息,设置合理的跟踪止损初始值 self.update_stop_order_dict(instrument_id, 'long', self.Lots, entry_price, sl_price, tp_price, initial_trailing_stop) self.pos = 1 # 更新全局持仓状态 # 兼容旧代码 self.long_trailing_stop_price = initial_trailing_stop self.sl_long_price = sl_price self.save_to_csv(instrument_id) elif action == '开空' and current_stops['short']['position'] <= 0: # 如果持有多头头寸,先平多 if current_stops['long']['position'] > 0: print('执行平多操作') self.insert_order(data['ExchangeID'], data['InstrumentID'], data['BidPrice1']-self.py, current_stops['long']['position'], b'1', b'3') # 清空多头持仓信息 self.clear_position_info(instrument_id, 'long') # 开空 print('执行开空操作') entry_price = float(data['BidPrice1']) self.insert_order(data['ExchangeID'], data['InstrumentID'], entry_price-self.py, self.Lots, b'1', b'0') # 使用AI建议的止损止盈价格 sl_price = stop_loss if stop_loss > 0 else entry_price * (1 + self.fixed_stop_loss_percent) tp_price = take_profit if take_profit > 0 else entry_price * (1 - self.trailing_stop_percent) # 设置初始跟踪止损价,与开仓价保持一定距离 initial_trailing_stop = entry_price * (1 + self.trailing_stop_percent) print(f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%") # 更新空头持仓信息,设置合理的跟踪止损初始值 self.update_stop_order_dict(instrument_id, 'short', self.Lots, entry_price, sl_price, tp_price, initial_trailing_stop) self.pos = -1 # 更新全局持仓状态 # 兼容旧代码 self.short_trailing_stop_price = initial_trailing_stop self.sl_shor_price = sl_price self.save_to_csv(instrument_id) elif action == '平多' and current_stops['long']['position'] > 0: print('执行平多操作') self.insert_order(data['ExchangeID'], data['InstrumentID'], data['BidPrice1']-self.py, current_stops['long']['position'], b'1', b'3') # 清空多头持仓信息 self.clear_position_info(instrument_id, 'long') elif action == '平空' and current_stops['short']['position'] > 0: print('执行平空操作') self.insert_order(data['ExchangeID'], data['InstrumentID'], data['AskPrice1']+self.py, current_stops['short']['position'], b'0', b'3') # 清空空头持仓信息 self.clear_position_info(instrument_id, 'short') # 如果AI建议调整止损止盈价格 elif action == '不操作': if stop_loss > 0: if current_stops['long']['position'] > 0: # 多头持仓 self.update_stop_order_dict(instrument_id, 'long', None, None, stop_loss, None, None) print(f'已调整多头止损价: {stop_loss}') # 兼容旧代码 self.sl_long_price = stop_loss self.save_to_csv(instrument_id) elif current_stops['short']['position'] > 0: # 空头持仓 self.update_stop_order_dict(instrument_id, 'short', None, None, stop_loss, None, None) print(f'已调整空头止损价: {stop_loss}') # 兼容旧代码 self.sl_shor_price = stop_loss self.save_to_csv(instrument_id) if take_profit > 0: if current_stops['long']['position'] > 0: # 多头持仓 self.update_stop_order_dict(instrument_id, 'long', None, None, None, take_profit, None) print(f'已调整多头止盈价: {take_profit}') # 兼容旧代码 self.long_trailing_stop_price = take_profit self.save_to_csv(instrument_id) elif current_stops['short']['position'] > 0: # 空头持仓 self.update_stop_order_dict(instrument_id, 'short', None, None, None, take_profit, None) print(f'已调整空头止盈价: {take_profit}') # 兼容旧代码 self.short_trailing_stop_price = take_profit self.save_to_csv(instrument_id) print("===== 交易信号执行完成 =====\n") else: print(f"信号置信度{confidence}低于执行阈值(5),不执行交易") print("===== 交易信号处理完成 =====\n") #公众号:松鼠Quant #主页:www.quant789.com #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 #注意:运行前请先安装好algoplus, # pip install AlgoPlus #http://www.algo.plus/ctp/python/0103001.html def format_data_for_llm(self, df): """ 将DataFrame格式化为适合LLM分析的文本格式,包含历史交易信息 """ # 提取最近几条记录 recent_data = df.tail(self.trader_rows) # 构建基本信息 data_text = "订单流数据分析:\n\n" # 提取最新行情数据 instrument_id = recent_data['symbol'].iloc[-1] # 添加最新价格和交易量信息 data_text += f"当前时间: {recent_data['datetime'].iloc[-1]}\n" data_text += f"当前价格: {recent_data['close'].iloc[-1]}\n" data_text += f"开盘价: {recent_data['open'].iloc[-1]}\n" data_text += f"最高价: {recent_data['high'].iloc[-1]}\n" data_text += f"最低价: {recent_data['low'].iloc[-1]}\n" data_text += f"成交量: {recent_data['volume'].iloc[-1]}\n" # 计算价格趋势 if len(recent_data) >= 5: price_trend = recent_data['close'].pct_change().tail(5).mean() * 100 data_text += f"价格短期趋势: {'上涨' if price_trend > 0 else '下跌'} ({price_trend:.2f}%)\n" # 计算价格波动性 if len(recent_data) >= 5: volatility = recent_data['close'].pct_change().tail(5).std() * 100 data_text += f"价格波动性: {volatility:.2f}%\n" # 添加支撑和阻力位分析 recent_high = recent_data['high'].max() recent_low = recent_data['low'].min() data_text += f"近期阻力位: {recent_high}\n" data_text += f"近期支撑位: {recent_low}\n" # 添加均线分析 - 计算5、10、20均线 if len(df) >= 20: # 计算均线 ma5 = df['close'].rolling(5).mean().iloc[-1] ma10 = df['close'].rolling(10).mean().iloc[-1] ma20 = df['close'].rolling(20).mean().iloc[-1] data_text += f"MA5: {ma5:.2f}\n" data_text += f"MA10: {ma10:.2f}\n" data_text += f"MA20: {ma20:.2f}\n" # 判断均线形态 if abs(ma5 - ma10) / ma10 < 0.001 and abs(ma10 - ma20) / ma20 < 0.001: ma_pattern = "均线粘合" elif ma5 > ma10 and ma10 > ma20: ma_pattern = "多头排列" elif ma5 < ma10 and ma10 < ma20: ma_pattern = "空头排列" elif ma5 > ma10 and ma10 < ma20: ma_pattern = "金叉形态" elif ma5 < ma10 and ma10 > ma20: ma_pattern = "死叉形态" else: ma_pattern = "无明显形态" data_text += f"均线形态: {ma_pattern}\n" # 价格与均线关系 current_price = df['close'].iloc[-1] data_text += f"价格相对MA5: {'上方' if current_price > ma5 else '下方'} ({(current_price/ma5-1)*100:.2f}%)\n" data_text += f"价格相对MA10: {'上方' if current_price > ma10 else '下方'} ({(current_price/ma10-1)*100:.2f}%)\n" data_text += f"价格相对MA20: {'上方' if current_price > ma20 else '下方'} ({(current_price/ma20-1)*100:.2f}%)\n" # 日内超涨超跌分析 if len(df) >= 20: # 计算日内振幅 daily_high = df['high'].iloc[-20:].max() daily_low = df['low'].iloc[-20:].min() daily_range = (daily_high - daily_low) / daily_low * 100 # 当前价格在日内范围的位置 current_in_range = (df['close'].iloc[-1] - daily_low) / (daily_high - daily_low) * 100 if (daily_high - daily_low) > 0 else 50 data_text += f"日内振幅: {daily_range:.2f}%\n" data_text += f"价格在日内范围的位置: {current_in_range:.2f}% (0%为日低, 100%为日高)\n" # 判断超涨超跌 if current_in_range > 85: data_text += "日内状态: 可能超涨\n" elif current_in_range < 15: data_text += "日内状态: 可能超跌\n" else: data_text += "日内状态: 正常区间\n" # 形态识别 if len(df) >= 20: # 简单K线形态识别 recent_k = df.tail(5).copy() # 计算实体和影线 recent_k['body'] = abs(recent_k['close'] - recent_k['open']) recent_k['upper_shadow'] = recent_k.apply(lambda x: x['high'] - max(x['open'], x['close']), axis=1) recent_k['lower_shadow'] = recent_k.apply(lambda x: min(x['open'], x['close']) - x['low'], axis=1) # 最新K线特征 latest_k = recent_k.iloc[-1] prev_k = recent_k.iloc[-2] if len(recent_k) > 1 else None data_text += "\nK线形态分析:\n" # 判断最新K线类型 if latest_k['body'] == 0: k_type = "十字星" elif latest_k['upper_shadow'] > 2 * latest_k['body'] and latest_k['lower_shadow'] < 0.5 * latest_k['body']: k_type = "上影线长" elif latest_k['lower_shadow'] > 2 * latest_k['body'] and latest_k['upper_shadow'] < 0.5 * latest_k['body']: k_type = "下影线长" elif latest_k['close'] > latest_k['open'] and latest_k['body'] > np.mean(recent_k['body']): k_type = "大阳线" elif latest_k['close'] < latest_k['open'] and latest_k['body'] > np.mean(recent_k['body']): k_type = "大阴线" elif latest_k['close'] > latest_k['open']: k_type = "小阳线" elif latest_k['close'] < latest_k['open']: k_type = "小阴线" else: k_type = "普通K线" data_text += f"最新K线类型: {k_type}\n" # 判断简单组合形态 if prev_k is not None: if prev_k['close'] < prev_k['open'] and latest_k['close'] > latest_k['open'] and latest_k['open'] <= prev_k['close'] and latest_k['close'] > prev_k['open']: data_text += "组合形态: 可能构成看涨吞没形态\n" elif prev_k['close'] > prev_k['open'] and latest_k['close'] < latest_k['open'] and latest_k['open'] >= prev_k['close'] and latest_k['close'] < prev_k['open']: data_text += "组合形态: 可能构成看跌吞没形态\n" elif prev_k['close'] < prev_k['open'] and latest_k['close'] > latest_k['open'] and latest_k['body'] > 1.5 * prev_k['body']: data_text += "组合形态: 可能构成看涨势能增强\n" elif prev_k['close'] > prev_k['open'] and latest_k['close'] < latest_k['open'] and latest_k['body'] > 1.5 * prev_k['body']: data_text += "组合形态: 可能构成看跌势能增强\n" # 添加订单流特定数据 data_text += f"\n订单流净值: {recent_data['delta'].iloc[-1]}\n" data_text += f"订单流累计值: {recent_data['delta累计'].iloc[-1] if 'delta累计' in recent_data.columns else '无数据'}\n" data_text += f"堆积指标: {recent_data['dj'].iloc[-1]}\n" # 添加日均线数据 data_text += f"日均线: {recent_data['dayma'].iloc[-1] if 'dayma' in recent_data.columns else '无数据'}\n" # 添加价格与日均线的关系 if 'dayma' in recent_data.columns: price_above_ma = recent_data['close'].iloc[-1] > recent_data['dayma'].iloc[-1] data_text += f"价格位于日均线: {'上方' if price_above_ma else '下方'}\n" # 订单流全面分析 data_text += "\n订单流详细分析:\n" # 计算订单流趋势 if len(recent_data) >= 5: delta_values = recent_data['delta'].values delta_trend = np.mean(np.diff(delta_values)) if len(delta_values) > 1 else 0 data_text += f"订单流趋势: {'增强中' if delta_trend > 0 else '减弱中'} (变化率: {delta_trend:.2f})\n" # 计算订单流强度(使用绝对值的平均值) delta_strength = np.mean(np.abs(recent_data['delta'].values)) data_text += f"订单流强度: {delta_strength:.2f}\n" # 订单流指标超涨超跌分析 if len(df) >= 20: delta_values = df['delta'].iloc[-20:].values delta_mean = np.mean(delta_values) delta_std = np.std(delta_values) current_delta = df['delta'].iloc[-1] # Z分数计算 if delta_std > 0: delta_z = (current_delta - delta_mean) / delta_std data_text += f"订单流偏离度(Z分数): {delta_z:.2f}\n" if delta_z > 2: data_text += "订单流状态: 可能超买\n" elif delta_z < -2: data_text += "订单流状态: 可能超卖\n" else: data_text += "订单流状态: 正常区间\n" # 买卖力量对比 if 'bid_v' in recent_data.columns and 'ask_v' in recent_data.columns: bid_power = recent_data['bid_v'].mean() ask_power = recent_data['ask_v'].mean() power_ratio = bid_power / ask_power if ask_power != 0 else float('inf') data_text += f"买卖比例: {power_ratio:.2f} (>1买方强势,<1卖方强势)\n" # 订单流累计趋势 if 'delta累计' in recent_data.columns and len(recent_data) >= 2: cumulative_start = recent_data['delta累计'].iloc[0] cumulative_end = recent_data['delta累计'].iloc[-1] cumulative_change = cumulative_end - cumulative_start data_text += f"累计订单流变化: {cumulative_change:.2f} (从 {cumulative_start:.2f} 到 {cumulative_end:.2f})\n" # 订单流波动性 delta_volatility = np.std(recent_data['delta'].values) data_text += f"订单流波动性: {delta_volatility:.2f}\n" # 订单流与价格相关性 if len(recent_data) >= 10: # 确保有足够数据计算相关性 price_changes = recent_data['close'].pct_change().dropna() delta_changes = recent_data['delta'].iloc[1:].reset_index(drop=True) # 对齐索引 if len(price_changes) > 0 and len(delta_changes) == len(price_changes): try: correlation = np.corrcoef(price_changes, delta_changes)[0, 1] if len(price_changes) > 1 else 0 data_text += f"订单流与价格相关性: {correlation:.2f}\n" data_text += f"相关性解读: {'强正相关' if correlation > 0.7 else '正相关' if correlation > 0.3 else '弱相关' if correlation > -0.3 else '负相关' if correlation > -0.7 else '强负相关'}\n" except: data_text += "订单流与价格相关性: 计算错误\n" # 订单流势能分析(最近几分钟的方向) recent_deltas = recent_data['delta'].tail(5).values positive_count = sum(1 for x in recent_deltas if x > 0) negative_count = sum(1 for x in recent_deltas if x < 0) data_text += f"最近订单流方向: {'多头主导' if positive_count > negative_count else '空头主导' if positive_count < negative_count else '方向不明'} ({positive_count}正/{negative_count}负)\n" # 订单流强弱可视化 delta_last_5 = recent_data['delta'].tail(5).values strength_visual = "" for val in delta_last_5: if val > 3: strength_visual += "↑↑ " elif val > 0: strength_visual += "↑ " elif val < -3: strength_visual += "↓↓ " elif val < 0: strength_visual += "↓ " else: strength_visual += "→ " data_text += f"订单流强弱可视化 (最近5分钟): {strength_visual}\n" # 添加最近几条记录的趋势 data_text += "\n最近几条记录的趋势:\n" # 添加最近5条记录的关键指标变化 for i in range(min(5, len(recent_data))): idx = -(i+1) data_text += f"记录 {i+1}: 时间={recent_data['datetime'].iloc[idx]}, 价格={recent_data['close'].iloc[idx]}, " data_text += f"订单流净值={recent_data['delta'].iloc[idx]}, 堆积={recent_data['dj'].iloc[idx]}\n" # 添加当前持仓信息,使用新的止盈止损字典 data_text += "\n当前持仓状态:\n" # 获取该合约的止盈止损信息 stops = self.stop_order_dict.get(instrument_id, { 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} }) # 获取多头和空头持仓信息 long_pos = stops.get('long', {}).get('position', 0) short_pos = stops.get('short', {}).get('position', 0) # 判断当前持仓方向 if long_pos > 0: data_text += f"持仓方向: 多头\n" data_text += f"持仓数量: {long_pos}\n" data_text += f"开仓价格: {stops['long']['entry_price']}\n" data_text += f"止损价格: {stops['long']['stop_loss']}\n" data_text += f"止盈价格: {stops['long']['take_profit']}\n" data_text += f"跟踪止损价: {stops['long']['trailing_stop']}\n" # 计算当前盈亏 current_price = recent_data['close'].iloc[-1] profit_percent = (current_price - stops['long']['entry_price']) / stops['long']['entry_price'] * 100 data_text += f"当前盈亏: {profit_percent:.2f}%\n" elif short_pos > 0: data_text += f"持仓方向: 空头\n" data_text += f"持仓数量: {short_pos}\n" data_text += f"开仓价格: {stops['short']['entry_price']}\n" data_text += f"止损价格: {stops['short']['stop_loss']}\n" data_text += f"止盈价格: {stops['short']['take_profit']}\n" data_text += f"跟踪止损价: {stops['short']['trailing_stop']}\n" # 计算当前盈亏 current_price = recent_data['close'].iloc[-1] profit_percent = (stops['short']['entry_price'] - current_price) / stops['short']['entry_price'] * 100 data_text += f"当前盈亏: {profit_percent:.2f}%\n" else: data_text += "持仓方向: 空仓\n" data_text += "持仓数量: 0\n" # 添加风险管理参数信息 data_text += "\n风险管理参数设置:\n" data_text += f"固定止损百分比: {self.fixed_stop_loss_percent * 100:.2f}%\n" data_text += f"跟踪止损百分比: {self.trailing_stop_percent * 100:.2f}%\n" # 添加交易建议提示 data_text += "\n请根据以上信息,分析当前市场状态并给出交易建议。需要考虑:\n" data_text += "1. 当前持仓状态是否合理\n" data_text += "2. 是否需要调整止损止盈位置\n" data_text += "3. 是否需要平仓或反手\n" data_text += "4. 是否适合开新仓\n" data_text += "5. 是否需要调整跟踪止损百分比参数(范围建议:0.0001-0.001)\n" data_text += "6. 是否出现抄底摸顶机会\n" data_text += "7. 是否存在日内波段交易机会\n" return data_text def update_stop_order_dict(self, instrument_id, direction, position, entry_price=None, stop_loss=None, take_profit=None, trailing_stop=None): """ 更新止盈止损字典 Args: instrument_id: 合约ID direction: 方向 'long' 或 'short' position: 持仓手数 entry_price: 开仓价格 stop_loss: 止损价格 take_profit: 止盈价格 trailing_stop: 跟踪止损价格 """ # 确保合约ID在字典中存在 if instrument_id not in self.stop_order_dict: self.stop_order_dict[instrument_id] = { 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} } # 更新指定方向的数据,仅更新提供的参数 if position is not None: self.stop_order_dict[instrument_id][direction]['position'] = position if entry_price is not None: self.stop_order_dict[instrument_id][direction]['entry_price'] = entry_price if stop_loss is not None: self.stop_order_dict[instrument_id][direction]['stop_loss'] = stop_loss if take_profit is not None: self.stop_order_dict[instrument_id][direction]['take_profit'] = take_profit if trailing_stop is not None: self.stop_order_dict[instrument_id][direction]['trailing_stop'] = trailing_stop # 保存到文件 self.save_stop_orders_to_file(instrument_id) def save_stop_orders_to_file(self, instrument_id): """将止盈止损信息保存到文件""" # 使用完整的合约代码 symbol = str(instrument_id) folder_path = "traderdata" file_path = os.path.join(folder_path, f"{symbol}_stops.json") # 如果文件夹不存在则创建 if not os.path.exists(folder_path): os.makedirs(folder_path) # 保存字典到JSON文件 with open(file_path, 'w') as f: json.dump(self.stop_order_dict.get(instrument_id, {}), f, indent=4) # 获取该合约的止盈止损信息 stops = self.stop_order_dict.get(instrument_id, { 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} }) # 打印详细信息 print(f"\n===== 已更新止盈止损信息: {instrument_id} =====") print(f"多头持仓: {stops['long']['position']} 手") print(f"多头入场价: {stops['long']['entry_price']}") print(f"多头止损价: {stops['long']['stop_loss']}") print(f"多头止盈价: {stops['long']['take_profit']}") print(f"多头跟踪止损: {stops['long']['trailing_stop']}") print(f"空头持仓: {stops['short']['position']} 手") print(f"空头入场价: {stops['short']['entry_price']}") print(f"空头止损价: {stops['short']['stop_loss']}") print(f"空头止盈价: {stops['short']['take_profit']}") print(f"空头跟踪止损: {stops['short']['trailing_stop']}") print("======================================\n") def load_stop_orders_from_file(self, instrument_id): """从文件加载止盈止损信息""" # 如果合约ID已经在字典中,直接返回,避免重复加载 if instrument_id in self.stop_order_dict: return True # 使用完整的合约代码 symbol = str(instrument_id) folder_path = "traderdata" file_path = os.path.join(folder_path, f"{symbol}_stops.json") if os.path.exists(file_path): try: with open(file_path, 'r') as f: stops_data = json.load(f) # 更新字典 self.stop_order_dict[instrument_id] = stops_data print(f"首次加载止盈止损信息: {instrument_id}") return True except Exception as e: print(f"加载止盈止损信息失败: {e}") # 如果文件不存在,初始化空字典结构 if instrument_id not in self.stop_order_dict: self.stop_order_dict[instrument_id] = { 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} } print(f"初始化止盈止损结构: {instrument_id}") return False def check_stop_conditions(self, data): """检查是否满足止盈止损条件""" instrument_id = data['InstrumentID'].decode() # 如果该合约不在止盈止损字典中,直接返回 if instrument_id not in self.stop_order_dict: return current_bid = float(data['BidPrice1']) # 当前买价 current_ask = float(data['AskPrice1']) # 当前卖价 stops = self.stop_order_dict[instrument_id] # 检查多头止盈止损 if stops['long']['position'] > 0: # 检查止损 if stops['long']['stop_loss'] > 0 and current_bid <= stops['long']['stop_loss']: print(f"触发多头止损: {instrument_id}, 价格: {current_bid}, 止损价: {stops['long']['stop_loss']}") self.insert_order(data['ExchangeID'], data['InstrumentID'], current_bid-self.py, stops['long']['position'], b'1', b'3') # 清空多头持仓信息 self.clear_position_info(instrument_id, 'long') self.pos = 0 # 更新全局持仓状态 # 检查跟踪止损 - 新增的逻辑 elif stops['long']['trailing_stop'] > 0 and current_bid < stops['long']['trailing_stop']: print(f"触发多头跟踪止损: {instrument_id}, 价格: {current_bid}, 跟踪止损价: {stops['long']['trailing_stop']}") self.insert_order(data['ExchangeID'], data['InstrumentID'], current_bid-self.py, stops['long']['position'], b'1', b'3') # 清空多头持仓信息 self.clear_position_info(instrument_id, 'long') self.pos = 0 # 更新全局持仓状态 # 检查止盈 elif stops['long']['take_profit'] > 0 and current_bid >= stops['long']['take_profit']: print(f"触发多头止盈: {instrument_id}, 价格: {current_bid}, 止盈价: {stops['long']['take_profit']}") self.insert_order(data['ExchangeID'], data['InstrumentID'], current_bid-self.py, stops['long']['position'], b'1', b'3') # 清空多头持仓信息 self.update_stop_order_dict(instrument_id, 'long', 0, 0, 0, 0) self.pos = 0 # 更新全局持仓状态 # 更新跟踪止损价 - 只在价格上涨时更新 elif stops['long']['trailing_stop'] > 0: # 只有当前价格比之前设置的跟踪止损价高一定幅度时才更新 new_trailing_stop = current_bid * (1 - self.trailing_stop_percent) if new_trailing_stop > stops['long']['trailing_stop']: self.update_stop_order_dict(instrument_id, 'long', None, None, None, None, new_trailing_stop) print(f"更新多头跟踪止损: {instrument_id}, 新止损价: {new_trailing_stop}") # 检查空头止盈止损 if stops['short']['position'] > 0: # 检查止损 if stops['short']['stop_loss'] > 0 and current_ask >= stops['short']['stop_loss']: print(f"触发空头止损: {instrument_id}, 价格: {current_ask}, 止损价: {stops['short']['stop_loss']}") self.insert_order(data['ExchangeID'], data['InstrumentID'], current_ask+self.py, stops['short']['position'], b'0', b'3') # 清空空头持仓信息 self.update_stop_order_dict(instrument_id, 'short', 0, 0, 0, 0, 0) self.pos = 0 # 更新全局持仓状态 # 检查跟踪止损 - 新增的逻辑 elif stops['short']['trailing_stop'] > 0 and current_ask > stops['short']['trailing_stop']: print(f"触发空头跟踪止损: {instrument_id}, 价格: {current_ask}, 跟踪止损价: {stops['short']['trailing_stop']}") self.insert_order(data['ExchangeID'], data['InstrumentID'], current_ask+self.py, stops['short']['position'], b'0', b'3') # 清空空头持仓信息 self.clear_position_info(instrument_id, 'short') self.pos = 0 # 更新全局持仓状态 # 检查止盈 elif stops['short']['take_profit'] > 0 and current_ask <= stops['short']['take_profit']: print(f"触发空头止盈: {instrument_id}, 价格: {current_ask}, 止盈价: {stops['short']['take_profit']}") self.insert_order(data['ExchangeID'], data['InstrumentID'], current_ask+self.py, stops['short']['position'], b'0', b'3') # 清空空头持仓信息 self.update_stop_order_dict(instrument_id, 'short', 0, 0, 0, 0, 0) self.pos = 0 # 更新全局持仓状态 # 更新跟踪止损价 - 只在价格下跌时更新 elif stops['short']['trailing_stop'] > 0: # 只有当前价格比之前设置的跟踪止损价低一定幅度时才更新 new_trailing_stop = current_ask * (1 + self.trailing_stop_percent) if new_trailing_stop < stops['short']['trailing_stop'] or stops['short']['trailing_stop'] == 0: self.update_stop_order_dict(instrument_id, 'short', None, None, None, None, new_trailing_stop) print(f"更新空头跟踪止损: {instrument_id}, 新止损价: {new_trailing_stop}") #保存数据 def clear_position_info(self, instrument_id, direction): """ 清空指定合约和方向的持仓信息 Args: instrument_id: 合约ID direction: 方向 'long' 或 'short' 或 'all' """ # 确保合约ID在字典中存在 if instrument_id not in self.stop_order_dict: return if direction == 'long' or direction == 'all': # 清空多头持仓信息 self.stop_order_dict[instrument_id]['long'] = { 'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0 } # 兼容旧代码 if direction == 'long': self.long_trailing_stop_price = 0 self.sl_long_price = 0 if direction == 'short' or direction == 'all': # 清空空头持仓信息 self.stop_order_dict[instrument_id]['short'] = { 'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0 } # 兼容旧代码 if direction == 'short': self.short_trailing_stop_price = 0 self.sl_shor_price = 0 # 同步全局持仓状态 if direction == 'all': self.pos = 0 self.long_trailing_stop_price = 0 self.short_trailing_stop_price = 0 self.sl_long_price = 0 self.sl_shor_price = 0 # 保存到文件 self.save_stop_orders_to_file(instrument_id) self.save_to_csv(instrument_id) print(f"已清空{instrument_id}的{direction}持仓信息") # 修改call_deepseek_model函数,移除JSON格式输出的要求,改为从普通文本响应中提取交易信号。 def call_deepseek_model(data_df, trader_instance, max_retries=2): """ 调用deepseek-r1大模型分析订单流数据 Args: data_df: 包含订单流数据的DataFrame trader_instance: MyTrader实例,用于访问持仓信息 max_retries: 最大重试次数 Returns: dict: 包含交易信号的字典 """ # 直接从环境变量获取API密钥 api_key = os.environ.get("OPENAI_API_KEY") or GLOBAL_LLM_CONFIG.get('api_key') base_url = GLOBAL_LLM_CONFIG.get('base_url', "https://api.deepseek.com") model_name = GLOBAL_LLM_CONFIG.get('model_name', "deepseek-reasoner") # 检查API密钥是否为空 if not api_key: print("错误: API密钥未设置,请在main函数中配置GLOBAL_LLM_CONFIG['api_key']") return {"action": "不操作", "reason": "API密钥未设置", "confidence": 0, "stop_loss": 0, "take_profit": 0} # 将DataFrame转换为可读性好的文本,传递trader_instance data_text = trader_instance.format_data_for_llm(data_df) # 构建提示词 prompt = f""" 作为期货交易员,基于以下市场数据做出交易决策: {data_text} 请重点考虑以下关键因素: 1. 均线形态(5、10、20均线)的排列状态及价格位置 2. 价格趋势、波动性与关键支撑阻力位 3. 日内超涨超跌状态,寻找高胜率反转交易机会 4. K线组合形态,尤其关注反转信号和动量变化 5. 订单流趋势变化与力度 6. 买卖力量对比和资金流向 7. 当前持仓状态与盈亏情况 8. 风险回报比与止损止盈设置合理性 9. 适合的交易时机与市场环境判断 【风险控制原则】: - 严格控制每笔交易亏损不超过本金的1% - 止损位设置应紧凑,一般不超过开仓价的0.3%-0.8% - 风险回报比至少为1:1.5,建议争取1:2或更高 - 在不明确的市场环境下,以保护资金为第一要务 请根据市场状态和持仓情况,给出明确的交易指令: 1. 交易方向: 开多/开空/平多/平空/不操作 2. 执行理由: 详细说明交易逻辑,结合技术形态、价格位置、订单流特征和市场状态,包括对当前持仓的处理方案 3. 置信度: 1-10的数字,必须是整数 4. 止损价: 明确的止损价格(必须是数字),确保亏损控制在合理范围内,不能过大 5. 止盈价: 明确的止盈价格(必须是数字),应至少是止损距离的1.5倍 6. 跟踪止损百分比: 0.0001-0.001之间的数字,根据市场波动性调整 请按以下格式返回交易决策,格式必须严格匹配: action: 开多/开空/平多/平空/不操作 reason: 交易理由 confidence: 置信度(1-10) stop_loss: 止损价 take_profit: 止盈价 trailing_percent: 跟踪止损百分比(0.0001-0.001) """ system_prompt = {"role": "system", "content": "你是一位经验丰富的期货交易员,拥有多年实盘交易经验,精通订单流分析和技术形态识别。你的交易风格注重实战执行,善于制定明确的入场出场策略和风险控制方案。特别擅长日内波段交易和抄底摸顶策略,能准确捕捉超涨超跌反转机会和均线形态变化带来的交易信号,并能迅速做出果断决策。你综合考虑市场情绪、技术指标与价格行为,在保护资金安全的前提下寻求最佳交易机会。根据当前市场状态和持仓情况,你能给出明确的交易执行方案、止损止盈设置以及仓位管理建议。请确保以指定的格式返回交易决策。"} # 添加重试机制 retries = 0 while retries <= max_retries: try: # 如果不是第一次尝试,输出重试信息 if retries > 0: print(f"正在进行第 {retries} 次重试...") # 调试信息 print(f"使用API参数: base_url={base_url}, model={model_name}") # 添加明显的提示信息,表示正在调用大模型API print("\n============================================") print("【正在调用大模型API进行交易分析,请稍候...】") print("============================================\n") # 记录开始时间 api_start_time = time.time() # 使用OpenAI客户端格式调用API client = OpenAI(api_key=api_key, base_url=base_url) response = client.chat.completions.create( model=model_name, messages=[ system_prompt, {"role": "user", "content": prompt} ], temperature=0.1, # 移除JSON格式输出的要求 max_tokens=8192, timeout=60 # 将超时时间从30秒增加到60秒 ) # 计算API调用耗时 api_elapsed = time.time() - api_start_time # 提取模型输出的内容 model_response = response.choices[0].message.content print(f"模型响应耗时: {api_elapsed:.2f}秒") print("模型响应前100字符: " + model_response[:100] + "...") # 添加明显的提示信息,表示API调用已完成 print("\n============================================") print("【大模型API调用完成】") print("============================================\n") # 从文本中解析出交易信号 try: trading_signal = parse_trading_signal(model_response) return trading_signal except Exception as parse_err: print(f"解析模型响应出错: {parse_err}") # 尝试从自由文本中提取关键信息 return extract_trading_signal_from_text(model_response) except Exception as e: retries += 1 if retries <= max_retries: print(f"调用大模型API出错: {e}") print(f"将在3秒后重试...") time.sleep(3) # 等待3秒后重试 else: print(f"已达到最大重试次数 ({max_retries}),调用大模型API失败") print(f"错误详情: {e}") print("\n请检查以下几点:") print("1. API密钥格式是否正确,应以'sk-'开头") print("2. 确认已安装最新版本的openai库: pip install --upgrade openai") print("3. 确认您的API密钥对应的模型是否为deepseek-reasoner") # 返回默认的不操作信号 return {"action": "不操作", "reason": f"API调用失败: {str(e)[:100]}", "confidence": 0, "stop_loss": 0, "take_profit": 0} # 如果所有重试都失败了,返回默认值 return {"action": "不操作", "reason": "API调用重试耗尽", "confidence": 0, "stop_loss": 0, "take_profit": 0} def parse_trading_signal(text): """ 从文本格式的模型响应中解析出交易信号 Args: text: 模型响应文本 Returns: dict: 包含交易信号的字典 """ lines = text.strip().split('\n') trading_signal = {} for line in lines: if ':' in line: key, value = line.split(':', 1) key = key.strip().lower() value = value.strip() if key == 'action': trading_signal['action'] = value elif key == 'reason': trading_signal['reason'] = value elif key == 'confidence': try: trading_signal['confidence'] = int(value) except ValueError: # 尝试从文本中提取数字 import re match = re.search(r'\d+', value) if match: trading_signal['confidence'] = int(match.group()) else: trading_signal['confidence'] = 0 elif key == 'stop_loss': try: trading_signal['stop_loss'] = float(value) except ValueError: # 尝试从文本中提取数字 import re match = re.search(r'\d+(\.\d+)?', value) if match: trading_signal['stop_loss'] = float(match.group()) else: trading_signal['stop_loss'] = 0 elif key == 'take_profit': try: trading_signal['take_profit'] = float(value) except ValueError: # 尝试从文本中提取数字 import re match = re.search(r'\d+(\.\d+)?', value) if match: trading_signal['take_profit'] = float(match.group()) else: trading_signal['take_profit'] = 0 elif key == 'trailing_percent' or key == 'trailing_stop_percent': try: value_float = float(value) # 确保值在合理范围内 if 0.0005 <= value_float <= 0.015: trading_signal['trailing_percent'] = value_float else: # 如果值不在预期范围内,尝试判断是否使用了百分比格式 if value_float >= 0.05 and value_float <= 1.5: # 可能是百分比格式,转换为小数 trading_signal['trailing_percent'] = value_float / 100 else: # 设置为默认值 trading_signal['trailing_percent'] = 0.005 except ValueError: # 尝试从文本中提取数字 import re match = re.search(r'\d+(\.\d+)?', value) if match: try: trailing_value = float(match.group()) if trailing_value >= 0.5 and trailing_value <= 10: trading_signal['trailing_percent'] = trailing_value / 100 else: trading_signal['trailing_percent'] = trailing_value except: trading_signal['trailing_percent'] = 0.02 else: trading_signal['trailing_percent'] = 0.02 # 检查是否有缺失的字段,如果有,设置默认值 if 'action' not in trading_signal: trading_signal['action'] = '不操作' if 'reason' not in trading_signal: trading_signal['reason'] = '未提供理由' if 'confidence' not in trading_signal: trading_signal['confidence'] = 0 if 'stop_loss' not in trading_signal: trading_signal['stop_loss'] = 0 if 'take_profit' not in trading_signal: trading_signal['take_profit'] = 0 if 'trailing_percent' not in trading_signal: trading_signal['trailing_percent'] = 0.005 # 修改默认值 return trading_signal def extract_trading_signal_from_text(text): """ 从自由格式文本中尝试提取交易信号 Args: text: 模型响应文本 Returns: dict: 包含交易信号的字典 """ # 默认交易信号 trading_signal = { "action": "不操作", "reason": "无法解析模型响应", "confidence": 0, "stop_loss": 0, "take_profit": 0, "trailing_percent": 0.005 # 更新默认的跟踪止损百分比 } # 尝试判断交易方向 text_lower = text.lower() if "开多" in text_lower: trading_signal["action"] = "开多" elif "开空" in text_lower: trading_signal["action"] = "开空" elif "平多" in text_lower: trading_signal["action"] = "平多" elif "平空" in text_lower: trading_signal["action"] = "平空" elif "不操作" in text_lower or "观望" in text_lower: trading_signal["action"] = "不操作" # 尝试从文本中提取置信度 import re confidence_matches = re.findall(r'置信度[::]\s*(\d+)', text_lower) if confidence_matches: try: trading_signal["confidence"] = int(confidence_matches[0]) except ValueError: pass # 尝试提取止损价 stop_loss_matches = re.findall(r'止损价[::]\s*(\d+(\.\d+)?)', text_lower) if stop_loss_matches: try: trading_signal["stop_loss"] = float(stop_loss_matches[0][0]) except ValueError: pass # 尝试提取止盈价 take_profit_matches = re.findall(r'止盈价[::]\s*(\d+(\.\d+)?)', text_lower) if take_profit_matches: try: trading_signal["take_profit"] = float(take_profit_matches[0][0]) except ValueError: pass # 尝试提取跟踪止损百分比 trailing_matches = re.findall(r'跟踪止损百分比[::]\s*(\d+(\.\d+)?)', text_lower) if not trailing_matches: trailing_matches = re.findall(r'跟踪百分比[::]\s*(\d+(\.\d+)?)', text_lower) if trailing_matches: try: trailing_value = float(trailing_matches[0][0]) # 判断是否为百分比格式 if trailing_value >= 0.5 and trailing_value <= 10: trading_signal["trailing_percent"] = trailing_value / 100 else: trading_signal["trailing_percent"] = trailing_value except ValueError: pass # 提取理由 reason_matches = re.findall(r'理由[::]\s*(.*?)(?=\n|$)', text_lower) if reason_matches: trading_signal["reason"] = reason_matches[0] return trading_signal # 修改run_trader函数,不再传递llm_config参数 def run_trader(broker_id, td_server, investor_id, password, app_id, auth_code, md_queue=None, page_dir='', private_resume_type=2, public_resume_type=2, load_history=False, history_rows=1000,trader_rows=10): my_trader = MyTrader( broker_id, td_server, investor_id, password, app_id, auth_code, md_queue, page_dir, private_resume_type, public_resume_type ) # 设置历史数据加载参数 my_trader.load_history = load_history my_trader.history_rows = history_rows my_trader.trader_rows = trader_rows my_trader.Join() # 修改主函数中的配置和调用方式 if __name__ == '__main__': #公众号:松鼠Quant #主页:www.quant789.com #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 #注意:运行前请先安装好algoplus, # pip install AlgoPlus #http://www.algo.plus/ctp/python/0103001.html # 配置大模型参数 - 直接通过环境变量设置 import os # 设置您的实际API密钥 api_key = "" # 请确保使用有效的密钥 os.environ["OPENAI_API_KEY"] = api_key # 同时设置到全局变量中 GLOBAL_LLM_CONFIG['api_key'] = api_key GLOBAL_LLM_CONFIG['base_url'] = "https://api.deepseek.com" GLOBAL_LLM_CONFIG['model_name'] = "deepseek-reasoner" # 历史数据加载配置 LOAD_HISTORY = False # 是否加载历史数据 HISTORY_ROWS = 30 # 加载历史文件中数据量 TRADER_ROWS = 10 # 当tader_df里的数据大于10行时开始计算指标及触发AI模型 # 设置K线时间粒度 BAR_RESAMPLE_RULE = '1T' # 1分钟K线,可以修改为'5T'(5分钟),'15T'(15分钟)等,也可用'5S'(5秒),'30S'(30秒)或'1H'(1小时),'2H'(2小时),'4H'(4小时),'1D'(1天) # 测试API连接 print(f"测试API连接,使用密钥: {api_key[:5]}...{api_key[-5:]}") try: client = OpenAI(api_key=api_key, base_url="https://api.deepseek.com") response = client.chat.completions.create( model="deepseek-reasoner", messages=[ {"role": "system", "content": "你是一个助手"}, {"role": "user", "content": "测试"} ], stream=True, # 新增此行 max_tokens=10 ) print("API连接测试成功!") except Exception as e: print(f"API连接测试失败: {e}") import traceback traceback.print_exc() #用simnow模拟,不要忘记屏蔽下方实盘的future_account字典 future_account = get_simulate_account( investor_id='', # simnow账户,注意是登录账户的ID,SIMNOW个人首页查看 password='', # simnow密码 server_name='电信1', # 电信1、电信2、移动、TEST、N视界 subscribe_list=[b'au2506'], # 合约列表 ) # #实盘用这个,不要忘记屏蔽上方simnow的future_account字典 # future_account = FutureAccount( # broker_id='', # 期货公司BrokerID # server_dict={'TDServer': "ip:port", 'MDServer': 'ip:port'}, # TDServer为交易服务器,MDServer为行情服务器。服务器地址格式为"ip:port。" # reserve_server_dict={}, # 备用服务器地址 # investor_id='', # 账户 # password='', # 密码 # app_id='simnow_client_test', # 认证使用AppID # auth_code='0000000000000000', # 认证使用授权码 # subscribe_list=[b'rb2405'], # 订阅合约列表 # md_flow_path='./log', # MdApi流文件存储地址,默认MD_LOCATION # td_flow_path='./log', # TraderApi流文件存储地址,默认TD_LOCATION # ) print('开始',len(future_account.subscribe_list)) # 共享队列 share_queue = Queue(maxsize=200) # 行情进程 md_process = Process(target=run_tick_engine, args=(future_account, [share_queue])) # 交易进程 - 增加历史数据加载参数 trader_process = Process(target=run_trader, args=( future_account.broker_id, future_account.server_dict['TDServer'], future_account.investor_id, future_account.password, future_account.app_id, future_account.auth_code, share_queue, # 队列 future_account.td_flow_path, 2, # private_resume_type 2, # public_resume_type LOAD_HISTORY, # 传递历史数据加载参数 HISTORY_ROWS, # 传递历史数据行数参数 TRADER_ROWS, # 传递最低计算阈值 )) md_process.start() trader_process.start() md_process.join() trader_process.join()