'''
该代码的主要目的是处理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，用于实现交易相关的功能。
'''
from concurrent.futures import ThreadPoolExecutor
from multiprocessing import Process, Queue
import queue
import threading
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#, timedelta
from datetime import time as s_time
import operator
import time
import numpy as np
import os
import csv
# import re

# 加入邮件通知
import smtplib
from email.mime.text import MIMEText   # 导入 MIMEText 类发送纯文本邮件
from email.mime.multipart import MIMEMultipart     # 导入 MIMEMultipart 类发送带有附件的邮件
# from email.mime.application import MIMEApplication # 导入 MIMEApplication 类发送二进制附件

## 配置邮件信息
receivers = ["240884432@qq.com"]      # 设置邮件接收人地址
subject   = "模拟账户订单流策略交易信号"            # 设置邮件主题 
#text      = " "            # 设置邮件正文
# file_path = "test.txt"                                # 设置邮件附件文件路径

## 配置邮件服务器信息
smtp_server = "smtp.qq.com"     # 设置发送邮件的 SMTP 服务器地址
smtp_port   = 465               # 设置发送邮件的 SMTP 服务器端口号，一般为 25 端口 465
sender      = "240884432@qq.com"     # 设置发送邮件的邮箱地址
username    = "240884432@qq.com"     # 设置发送邮件的邮箱用户名
password    = "osjyjmbqrzxtbjbf"             #zrmpcgttataabhjh，设置发送邮件的邮箱密码或授权码

tickdatadict = {}  # 存储Tick数据的字典
quotedict = {}  # 存储行情数据的字典
ofdatadict = {}  # 存储K线数据的字典
trade_dfs = {} #pd.DataFrame({})  # 存储交易数据的DataFrame对象
previous_volume = {}  # 上一个Tick的成交量
tsymbollist={} #过渡tick

截面数据_资金流向={}
top_two_symbols=[]

# # Jerome:期货收盘时间交易品种
# clear_execute_dict = {'sc': s_time(2,30), 'bc': s_time(1,0), 'lu': s_time(23,0), 'nr': s_time(23,0),'au': s_time(2,30), 'ag': s_time(2,30),
#                       'ss': s_time(1,0), 'sn': s_time(1,0), 'ni': s_time(1,0), 'pb': s_time(1,0),'zn': s_time(1,0), 'al': s_time(1,0), 'cu': s_time(1,0),
#                       'ru': s_time(23,0), 'rb': s_time(23,0), 'hc': s_time(23,0), 'fu': s_time(23,0), 'bu': s_time(23,0), 'sp': s_time(23,0),
#                       'PF': s_time(23,0), 'SR': s_time(23,0), 'CF': s_time(23,0), 'CY': s_time(23,0), 'RM': s_time(23,0), 'MA': s_time(23,0),
#                       'TA': s_time(23,0), 'ZC': s_time(23,0), 'FG': s_time(23,0), 'OI': s_time(23,0), 'SA': s_time(23,0),
#                       'p': s_time(23,0), 'j': s_time(23,0), 'jm': s_time(23,0), 'i': s_time(23,0), 'l': s_time(23,0), 'v': s_time(23,0),
#                       'pp': s_time(23,0), 'eg': s_time(23,0), 'c': s_time(23,0), 'cs': s_time(23,0), 'y': s_time(23,0), 'm': s_time(23,0),
#                       'a': s_time(23,0), 'b': s_time(23,0), 'rr': s_time(23,0), 'eb': s_time(23,0), 'pg': s_time(23,0), 'SH': s_time(23,00)}

fees_df = pd.read_csv('./futures_fees_info.csv', header = 0, usecols= [1, 3, 5, 13, 15],names=['合约代码', '品种代码', '合约乘数', '做多保证金率', '做空保证金率'])
contacts_df = pd.read_csv('./main_contacts.csv', header = 0, usecols= [16, 17],names=['主连代码', '品种代码'])   
#交易程序---------------------------------------------------------------------------------------------------------------------------------------------------------------------
class ParamObj:
    # 策略需要用到的参数，在新建合约对象的时候传入！！
    symbol = None #合约名称
    Lots = None #下单手数
    py = None #设置委托价格的偏移，更加容易促成成交
    trailing_stop_percent = None #跟踪出场参数
    fixed_stop_loss_percent = None #固定出场参数
    dj_X = None #开仓的堆积参数
    delta = None #开仓的delta参数
    sum_delta = None #开仓的delta累积参数
    失衡=None
    堆积=None
    周期=None
    
    # 策略需要用到的变量
    cont_df = 0
    pos = 0 
    clearing_executed = False
    kgdata = True
    
    多头止损价格 = 0
    空头止损价格 = 0
    
    多头成本价格 = 0
    空头成本价格 = 0

    多头开仓历时=0
    空头开仓历时=0
    
    平_多时间=4
    平_空时间=4

    def __init__(self, symbol, Lots, py,dj_X, delta, sum_delta,失衡,堆积,周期,平_多时间,平_空时间):
        self.symbol = symbol
        self.Lots = Lots
        self.py = py
        self.dj_X = dj_X 
        self.delta = delta 
        self.sum_delta = sum_delta 
        self.失衡=失衡
        self.堆积=堆积
        self.周期=周期
        self.平_多时间=平_多时间
        self.平_空时间=平_空时间
    

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):
        self.param_dict = {}
        self.queue_dict = {}
        self.品种=' '


    def tickcome(self,md_queue):
        global previous_volume
        data=md_queue
        instrument_id = data['InstrumentID'].decode()  # 品种代码
        ActionDay = data['ActionDay'].decode()  # 交易日日期
        update_time = data['UpdateTime'].decode()  # 更新时间
        
        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']),  # 合约持仓量
        }
        # print('&&&&&&&&',instrument_id, tick['created_at'],'vol:',tick['last_volume'])
        # 更新上一个Tick的成交量
        previous_volume[instrument_id] = int(data['Volume'])
        if tick['last_volume']>0:
            #print(tick['created_at'],'vol:',tick['last_volume'])
            # 处理Tick数据
            self.on_tick(tick)

    def can_time(self,hour, minute):
        hour = str(hour)
        minute = str(minute)
        if len(minute) == 1:
            minute = "0" + minute
        return int(hour + minute)

    def on_tick(self,tick):
        
        # tm=self.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的买卖价和买卖量
        
            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)
        self.tickdata(tick_dt,sym)

    def data_of(self,symbol, df):
        global trade_dfs
        # 将df数据合并到trader_df中
        # if symbol not in trade_dfs.keys():
        #     trade_df = pd.DataFrame({})
        # else:
        #     trade_df = trade_dfs[symbol]
        trade_dfs[symbol] = pd.concat([trade_dfs[symbol], df], ignore_index=True)
        # print('!!!!!!!!!!!trader_df: ', symbol, df['datetime'].iloc[-1])
        #print(trader_df)

    def process(self,bidDict, askDict, symbol):
        try:
            # 尝试从quotedict中获取对应品种的报价数据
            dic = quotedict[symbol]
            bidDictResult = dic['bidDictResult']
            askDictResult = dic['askDictResult']
        except:  # noqa: E722
            # 如果获取失败，则初始化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

    def tickdata(self,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]
                        self.data_of(symbol, 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'])
        param = self.param_dict[self.品种]
        bardata = (
            tickdata.resample(
                on="bartime", rule=param.周期, 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
        self.orderflow_df_new(tickdata, bardata, symbol)

        # 保存tickdata数据到本地csv
        tickdata_file_path = f"tickdata/{str(symbol)}_tick.csv"
        directory = os.path.dirname(tickdata_file_path)
        if not os.path.exists(directory):
            os.makedirs(directory)
        if os.path.exists(tickdata_file_path):
            tickdata.tail(1).to_csv(tickdata_file_path, mode='a', header=False, index=False)
            f = open(tickdata_file_path, 'a')
            f.flush()
            # f.close()
        else:
            tickdata.to_csv(tickdata_file_path, index=False)
            f = open(tickdata_file_path, 'a')
            f.flush()
            # f.close()
        # time.sleep(0.5)

    def orderflow_df_new(self,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
        bp1minickArray = df_tick['bid_p'].values
        ap1minickArray = 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(bp1minickArray[0],4)
            Ap = round(ap1minickArray[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 = self.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'] = self.GetOrderFlow_dj(df)
            ofdatadict[symbol]=df

    def GetOrderFlow_dj(self,kData):
        param = self.param_dict[self.品种]
        Config = {
            'Value1': param.失衡,
            'Value2': param.堆积,
            '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'] is 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'] is 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

    def OnRtnTrade(self, pTrade):
        print("||成交回报||", pTrade)

    def OnRspOrderInsert(self, pInputOrder, pRspInfo, nRequestID, bIsLast):
        print("||OnRspOrderInsert||", pInputOrder, pRspInfo, nRequestID, bIsLast)

    # 订单状态通知
    def OnRtnOrder(self, pOrder):
        print("||订单回报||", pOrder)

    #保存OF数据
    def save_trade_data(self,df,instrument_id):
        # 定义文件路径
        csv_file_path = f"ofdata/{instrument_id}_ofdata.csv"
        directory = os.path.dirname(csv_file_path)
        
        # 检查目录是否存在，如果不存在则创建它
        if not os.path.exists(directory):
            os.makedirs(directory)
        
        # 如果文件夹存在，则追加数据；否则，创建新文件并保存整个 DataFrame
        if os.path.exists(csv_file_path):
            # 仅保存最后一行数据
            df.tail(1).to_csv(csv_file_path, mode='a', header=False, index=False)
        else:
            # 创建新文件并保存整个 DataFrame
            df.to_csv(csv_file_path, index=False)

    def w_log(self,symbol,log_message):

        # 创建文件夹（如果不存在）
        log_dir = 'tradelogs'
        if not os.path.exists(log_dir):
            os.makedirs(log_dir)
        
        # 写入日志到 CSV 文件
        now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        log_file = os.path.join(log_dir, f'{symbol}log.csv')
        # 打印日志到控制台
        print(f'{now}: {log_message}')
        with open(log_file, 'a', encoding='utf-8',newline='') as csvfile:
            writer = csv.writer(csvfile)
            # 如果文件为空，写入表头
            if csvfile.tell() == 0:
                writer.writerow(['time', 'logs'])
            writer.writerow([now, log_message])
            
    # 计算单品种资金流向数据
    def 资金流向计算(self,df):
        # 将 'delta' 和 'close' 转换为数值类型，强制转换错误
        df['delta'] = pd.to_numeric(df['delta'], errors='coerce')
        df['close'] = pd.to_numeric(df['close'], errors='coerce')

        # 删除 'delta' 或 'close' 中的 NaN 值
        df = df.dropna(subset=['delta', 'close'])
        symbol=df['symbol'].iloc[-1]
        # symbol = ''.join(filter(str.isalpha, symbol)).upper()
        # 资金净流向 = abs(sum(df['delta']*df['close']))*合约信息[symbol]['合约单位']*合约信息[symbol]['保证金']
        hycs = int(fees_df[fees_df['合约代码'] == symbol]['合约乘数'].iloc[0])
        bzj = (float(fees_df[fees_df['合约代码'] == symbol]['做多保证金率'].iloc[0]) + float(fees_df[fees_df['合约代码'] == symbol]['做空保证金率'].iloc[0]))/2
        # print("%s品种的合约乘数:%s,保证金率:%s"%(symbol,hycs,bzj))
        资金净流向 = abs(sum(df['delta']*df['close']))*hycs*bzj
        symbol = ''.join(filter(str.isalpha, symbol)).upper()
        更新状态=True
        # 将结果放入 DataFrame
        result_df = pd.DataFrame({
            '资金净流向': [资金净流向],
            '更新状态': [更新状态]
        })

        return result_df
    
    # 收盘清仓
    def 收盘清仓(self,symbol,data):
        param = self.param_dict[symbol]
        # 获取当前时间
        current_time = datetime.now().time()
        
        # 设置清仓操作的时间范围1：14:55到15:00
        clearing_time1_start = s_time(14, 55)
        clearing_time1_end = s_time(15, 0)

        # # 设置清仓操作的时间范围2：00:55到01:00
        # clearing_time2_start = s_time(22, 55)
        # clearing_time2_end = s_time(23, 0)
        
        # clearing_time3_start = s_time(0, 55)
        # clearing_time3_end = s_time(1, 0)

        # clearing_time4_start = s_time(2, 25)
        # clearing_time4_end = s_time(2, 30)

        # now = datetime.now()
        # 创建一个标志变量，用于记录是否已经执行过清仓操作
        #param.clearing_executed = False

        #jerome:增加修改合约代码识别
        # alpha_chars = ""
        # numeric_chars = ""
        # for char in symbol:
        elif clearing_time2_start <= current_time <= clearing_time2_end and not param.clearing_executed and commodity_night_dict[alpha_chars] == s_time(23,00):
        #         alpha_chars = char
        #     elif char.isdigit():
        #         numeric_chars = char

        # 检查当前时间是否在第一个清仓操作的时间范围内，并且清仓操作未执行过
        if clearing_time1_start <= current_time <= clearing_time1_end and not param.clearing_executed :
            #trade_dfs.drop(trade_dfs.index,inplace=True)#清除当天的行情数据
            if param.pos>0:
                #平多
                # self.insert_order(data['ExchangeID'], data['InstrumentID'], data['BidPrice1']-param.py,param.Lots,b'1',b'1')
                # self.insert_order(data['ExchangeID'], data['InstrumentID'], data['BidPrice1']-param.py,param.Lots,b'1',b'3')
                param.pos=0
                self.w_log(symbol,f"{symbol}多头清仓操作")
                # 发送邮件：
                text = f"14:55平多清仓交易： 交易品种为{data['InstrumentID']}, 反手平空的平仓价格为{data['BidPrice1']-param.py}, 交易手数位{param.Lots}"
                send_mail(text) 
                pass
            elif param.pos<0:
                #平空
                # self.insert_order(data['ExchangeID'], data['InstrumentID'], data['AskPrice1']+param.py,param.Lots,b'0',b'1')
                # self.insert_order(data['ExchangeID'], data['InstrumentID'], data['AskPrice1']+param.py,param.Lots,b'0',b'3')
                param.pos=0
                self.w_log(symbol,f"{symbol}空头清仓操作")
                # 发送邮件：
                text = f"14:55平空清仓交易： 交易品种为{data['InstrumentID']}, 反手平空的平仓价格为{data['AskPrice1']+param.py}, 交易手数位{param.Lots}"
                send_mail(text) 
                pass
            param.clearing_executed = True  # 设置标志变量为已执行

        # # 检查当前时间是否在第二个清仓操作的时间范围内，并且清仓操作未执行过
        # elif clearing_time2_start <= current_time <= clearing_time2_end and not param.clearing_executed and clear_execute_dict[alpha_chars] == s_time(23,00):
        #     #trade_dfs.drop(trade_dfs.index,inplace=True) #清除当天的行情数据
        #     if param.pos>0:
        #         #平多
        #         self.insert_order(data['ExchangeID'], data['InstrumentID'], data['BidPrice1']-param.py,param.Lots,b'1',b'1')
        #         self.insert_order(data['ExchangeID'], data['InstrumentID'], data['BidPrice1']-param.py,param.Lots,b'1',b'3')
        #         param.pos=0
        #         self.w_log(symbol,f"{symbol}多头清仓操作")
        #         # 发送邮件：
        #         text = f"22:55平多清仓交易： 交易品种为{data['InstrumentID']}, 反手平空的平仓价格为{data['BidPrice1']-param.py}, 交易手数位{param.Lots}"
        #         send_mail(text) 
        #         pass
        #     elif param.pos<0:
        #         #平空
        #         self.insert_order(data['ExchangeID'], data['InstrumentID'], data['AskPrice1']+param.py,param.Lots,b'0',b'1')
        #         self.insert_order(data['ExchangeID'], data['InstrumentID'], data['AskPrice1']+param.py,param.Lots,b'0',b'3')
        #         param.pos=0
        #         self.w_log(symbol,f"{symbol}空头清仓操作")
        #         # 发送邮件：
        #         text = f"22:55平空清仓交易： 交易品种为{data['InstrumentID']}, 反手平空的平仓价格为{data['AskPrice1']+param.py}, 交易手数位{param.Lots}"
        #         send_mail(text) 
        #         pass

        # # 检查当前时间是否在第三个清仓操作的时间范围内，并且清仓操作未执行过
        # elif clearing_time3_start <= current_time <= clearing_time3_end and not param.clearing_executed and clear_execute_dict[alpha_chars] == s_time(1,00):
        #     #trade_dfs.drop(trade_dfs.index,inplace=True) #清除当天的行情数据
        #     if param.pos>0:
        #         #平多
        #         self.insert_order(data['ExchangeID'], data['InstrumentID'], data['BidPrice1']-param.py,param.Lots,b'1',b'1')
        #         self.insert_order(data['ExchangeID'], data['InstrumentID'], data['BidPrice1']-param.py,param.Lots,b'1',b'3')
        #         param.pos=0
        #         self.w_log(f"{symbol}多头清仓操作")
        #         # 发送邮件：
        #         text = f"00:55平多清仓交易： 交易品种为{data['InstrumentID']}, 反手平空的平仓价格为{data['BidPrice1']-param.py}, 交易手数位{param.Lots}"
        #         send_mail(text) 
        #         pass
        #     elif param.pos<0:
        #         #平空
        #         self.insert_order(data['ExchangeID'], data['InstrumentID'], data['AskPrice1']+param.py,param.Lots,b'0',b'1')
        #         self.insert_order(data['ExchangeID'], data['InstrumentID'], data['AskPrice1']+param.py,param.Lots,b'0',b'3')
        #         param.pos=0
        #         self.w_log(f"{symbol}空头清仓操作")
        #         # 发送邮件：
        #         text = f"00:55平空清仓交易： 交易品种为{data['InstrumentID']}, 反手平空的平仓价格为{data['AskPrice1']+param.py}, 交易手数位{param.Lots}"
        #         send_mail(text) 
        #         pass

        # elif clearing_time4_start <= current_time <= clearing_time4_end and not param.clearing_executed and clear_execute_dict[alpha_chars] == s_time(2,30):
        #     #trade_dfs.drop(trade_dfs.index,inplace=True) #清除当天的行情数据
        #     if param.pos>0:
        #         #平多
        #         self.insert_order(data['ExchangeID'], data['InstrumentID'], data['BidPrice1']-param.py,param.Lots,b'1',b'1')
        #         self.insert_order(data['ExchangeID'], data['InstrumentID'], data['BidPrice1']-param.py,param.Lots,b'1',b'3')
        #         param.pos=0
        #         self.w_log(f"{symbol}多头清仓操作")
        #         # 发送邮件：
        #         text = f"2:25平多清仓交易： 交易品种为{data['InstrumentID']}, 反手平空的平仓价格为{data['BidPrice1']-param.py}, 交易手数位{param.Lots}"
        #         send_mail(text) 
        #         pass
        #     elif param.pos<0:
        #         #平空
        #         self.insert_order(data['ExchangeID'], data['InstrumentID'], data['AskPrice1']+param.py,param.Lots,b'0',b'1')
        #         self.insert_order(data['ExchangeID'], data['InstrumentID'], data['AskPrice1']+param.py,param.Lots,b'0',b'3')
        #         param.pos=0
        #         self.w_log(f"{symbol}空头清仓操作")
        #         # 发送邮件：
        #         text = f"2:25平空清仓交易： 交易品种为{data['InstrumentID']}, 反手平空的平仓价格为{data['AskPrice1']+param.py}, 交易手数位{param.Lots}"
        #         send_mail(text) 
        #         pass

        #     param.clearing_executed = True  # 设置标志变量为已执行
        # # 如果不在任何清仓操作的时间范围内，可以执行其他操作或不执行任何操作
        else:
            param.clearing_executed = False
            pass
            #print("不在清仓操作时间范围内")
        
        return param.clearing_executed
            
    def cal_sig(self, symbol_queue):
        while True:
            try:
                # now = datetime.now()
                data = symbol_queue.get(block=True, timeout=5)  # 如果5秒没收到新的tick行情，则抛出异常
                instrument_id = data['InstrumentID'].decode()  # 品种代码
                size = symbol_queue.qsize()
                if size > 1:
                    print(f'当前{instrument_id}共享队列长度为{size}, 有点阻塞！！！！！')
                param = self.param_dict[instrument_id]
                self.品种=instrument_id
                #OF计算数据开始
                self.tickcome(data)
                trade_df = trade_dfs[instrument_id]
                #清仓开关
                run_kg=self.收盘清仓(instrument_id,data)
                最新价=data['LastPrice']
                
                # #多头时间出场
                if param.pos>0 and param.多头开仓历时>param.平_多时间 :
                    #平多
                    # self.insert_order(data['ExchangeID'], data['InstrumentID'], data['BidPrice1']-param.py,param.Lots,b'1',b'1')
                    # self.insert_order(data['ExchangeID'], data['InstrumentID'], data['BidPrice1']-param.py,param.Lots,b'1',b'3')
                    param.pos=0
                    param.多头止损价格=0
                    param.多头开仓历时=0
                    param.多头成本价格=0
                    self.w_log(instrument_id,f'历时{param.平_多时间}***多头***{self.品种}时间出场')
                    # 发送邮件
                    text = f"平多时间交易： 交易品种为{data['InstrumentID']}, 交易时间为{trade_df['datetime'].iloc[-1]}, 反手平多的平仓价格{data['BidPrice1']-param.py}, 交易手数位{param.Lots}"
                    send_mail(text) 
                
                #多头价格止损    
                if param.pos>0 and 最新价<param.多头止损价格 :
                    #平多
                    # self.insert_order(data['ExchangeID'], data['InstrumentID'], data['BidPrice1']-param.py,param.Lots,b'1',b'1')
                    # self.insert_order(data['ExchangeID'], data['InstrumentID'], data['BidPrice1']-param.py,param.Lots,b'1',b'3')
                    param.pos=0
                    param.多头止损价格=0
                    param.多头开仓历时=0
                    param.多头成本价格=0
                    self.w_log(instrument_id,f'多头止损触发: {最新价},多头止损价格：{param.多头止损价格} ***{instrument_id}多头止损***')  
                    # 发送邮件
                    text = f"平多止损交易： 交易品种为{data['InstrumentID']}, 交易时间为{trade_df['datetime'].iloc[-1]}, 反手平多的平仓价格{data['BidPrice1']-param.py}, 交易手数位{param.Lots}"
                    send_mail(text) 
                    
                # #多头跟踪止盈-----------------------暂时用不到------------------------
                # elif param.pos>0 and len(trade_df)>1 and 最新价<trade_df['10_MA'].iloc[-1] and 最新价>param.多头成本价格 :
                #     #平多
                #     self.insert_order(data['ExchangeID'], data['InstrumentID'], data['BidPrice1']-param.py,param.Lots,b'1',b'1')
                #     self.insert_order(data['ExchangeID'], data['InstrumentID'], data['BidPrice1']-param.py,param.Lots,b'1',b'3')
                #     param.pos=0
                #     param.多头止损价格=0
                #     param.多头开仓历时=0
                #     param.多头成本价格=0
                #     self.w_log(instrument_id,f'多头跟踪止盈触发: {最新价} ***{instrument_id}多头止盈***')   
                
                # # #空头时间出场
                if param.pos<0 and param.空头开仓历时>param.平_空时间 :
                    #平空
                    # self.insert_order(data['ExchangeID'], data['InstrumentID'], data['AskPrice1']+param.py,param.Lots,b'0',b'1')
                    # self.insert_order(data['ExchangeID'], data['InstrumentID'], data['AskPrice1']+param.py,param.Lots,b'0',b'3')
                    param.pos=0
                    param.空头止损价格=0
                    param.空头开仓历时=0
                    param.空头成本价格=0
                    self.w_log(instrument_id,f'历时{param.平_空时间}***空头***{self.品种}时间出场')
                    # 发送邮件
                    text = f"平空时间交易： 交易品种为{data['InstrumentID']}, 交易时间为{trade_df['datetime'].iloc[-1]}, 反手平空的平仓价格为{data['AskPrice1']+param.py}, 交易手数位{param.Lots}"
                    send_mail(text) 
                
                #空头价格止损
                if param.pos<0 and 最新价>param.空头止损价格 :
                    #平空
                    # self.insert_order(data['ExchangeID'], data['InstrumentID'], data['AskPrice1']+param.py,param.Lots,b'0',b'1')
                    # self.insert_order(data['ExchangeID'], data['InstrumentID'], data['AskPrice1']+param.py,param.Lots,b'0',b'3')
                    param.pos=0
                    param.空头止损价格=0
                    param.空头开仓历时=0
                    param.空头成本价格=0
                    self.w_log(instrument_id,f'空头止损触发: {最新价},空头止损价格：{param.空头止损价格} ***{instrument_id}空头止损***')  
                    # 发送邮件
                    text = f"平空止损交易： 交易品种为{data['InstrumentID']}, 交易时间为{trade_df['datetime'].iloc[-1]}, 反手平空的平仓价格为{data['AskPrice1']+param.py}, 交易手数位{param.Lots}"
                    send_mail(text)
                     
                # #空头跟踪止盈-----------------------暂时用不到------------------------
                # elif param.pos<0 and len(trade_df)>1 and 最新价>trade_df['10_MA'].iloc[-1] and 最新价<param.空头成本价格 :
                #     #平空
                #     self.insert_order(data['ExchangeID'], data['InstrumentID'], data['AskPrice1']+param.py,param.Lots,b'0',b'1')
                #     self.insert_order(data['ExchangeID'], data['InstrumentID'], data['AskPrice1']+param.py,param.Lots,b'0',b'3')
                #     param.pos=0
                #     param.空头止损价格=0
                #     param.空头开仓历时=0
                #     param.空头成本价格=0
                #     self.w_log(instrument_id,f'空头跟踪止盈触发: {最新价},***{instrument_id}空头止盈***')                
                                 
                #交易程序开始
                if len(trade_df)>param.cont_df and run_kg is False: 
                    #开仓历时更新：
                    if param.pos>0:
                        param.多头开仓历时+=1
                    elif param.pos<0:
                        param.空头开仓历时+=1
                        
                    #计算截面数据
                    截面数据_资金流向[instrument_id]=self.资金流向计算(trade_df)
                        
                    #日均线
                    trade_df['dayma']=trade_df['close'].mean()
                    
                    # 计算5日均线和10日均线，即使数据不足5日或10日
                    trade_df['5_MA'] = trade_df['close'].rolling(window=5, min_periods=1).mean()
                    trade_df['10_MA'] = trade_df['close'].rolling(window=10, min_periods=1).mean()

                    # 计算累积的delta值
                    trade_df['delta'] = trade_df['delta'].astype(float)
                    trade_df['delta累计'] = trade_df['delta'].cumsum()

                    #大于日均线
                    开多1=trade_df['dayma'].iloc[-1] > 0 and trade_df['close'].iloc[-1] > trade_df['dayma'].iloc[-1]  

                    #累计多空净量大于X
                    开多4=trade_df['delta累计'].iloc[-1] > param.sum_delta and trade_df['delta'].iloc[-1] > param.delta
                
                    #小于日均线
                    开空1=trade_df['dayma'].iloc[-1]>0 and trade_df['close'].iloc[-1] < trade_df['dayma'].iloc[-1] 

                    #累计多空净量小于X 
                    开空4=trade_df['delta累计'].iloc[-1] < -param.sum_delta and trade_df['delta'].iloc[-1] < -param.delta 
                                           
                    开多组合= 开多1 and 开多4 and trade_df['dj'].iloc[-1]>param.dj_X and trade_df['5_MA'].iloc[-1] > trade_df['10_MA'].iloc[-1]
                    开空条件= 开空1 and 开空4 and trade_df['dj'].iloc[-1]<-param.dj_X and trade_df['5_MA'].iloc[-1] < trade_df['10_MA'].iloc[-1]
                    
                    #开平仓
                    #换仓平多
                    if param.pos>0 and instrument_id not in top_two_symbols:
                        # self.insert_order(data['ExchangeID'], data['InstrumentID'], data['BidPrice1']-param.py,param.Lots,b'1',b'1')
                        # self.insert_order(data['ExchangeID'], data['InstrumentID'], data['BidPrice1']-param.py,param.Lots,b'1',b'3')
                        param.pos=0
                        param.多头止损价格=0
                        param.多头开仓历时=0
                        param.多头成本价格=0
                        self.w_log(instrument_id,f'当前截面品种{top_two_symbols},{instrument_id}不在范围，***多平仓***')   
                        #发送邮件
                        text = f"换仓平多交易： 交易品种为{data['InstrumentID']}, 交易时间为{trade_df['datetime'].iloc[-1]}, 反手平多的平仓价格{data['BidPrice1']-param.py}, 交易手数位{param.Lots}"
                        send_mail(text) 
                    #多头开仓          
                    if param.pos==0 and 开多组合 and instrument_id in top_two_symbols :
                        #开多
                        # self.insert_order(data['ExchangeID'], data['InstrumentID'], data['AskPrice1']+param.py,param.Lots,b'0',b'0')
                        param.pos=1
                        param.多头止损价格=trade_df['low'].iloc[-2]
                        param.多头成本价格=data['AskPrice1']
                        param.多头开仓历时=1
                        self.w_log(instrument_id,f'品种：{instrument_id},委托价格: {param.多头成本价格}***开多***')
                        # 发送邮件
                        text = f"多头开仓交易： 交易品种为{data['InstrumentID']}, 交易时间为{trade_df['datetime'].iloc[-1]}, 多头开仓的开仓价格{data['AskPrice1']+param.py}, 交易手数位{param.Lots}"
                        send_mail(text) 
                    
                    #换仓平空
                    if param.pos<0 and instrument_id not in top_two_symbols :
                        
                        # self.insert_order(data['ExchangeID'], data['InstrumentID'], data['AskPrice1']+param.py,param.Lots,b'0',b'1')
                        # self.insert_order(data['ExchangeID'], data['InstrumentID'], data['AskPrice1']+param.py,param.Lots,b'0',b'3')
                        param.pos=0
                        param.空头止损价格=0
                        param.空头开仓历时=0
                        param.空头成本价格=0
                        self.w_log(instrument_id,f'当前截面品种{top_two_symbols},{instrument_id}不在范围，***空平仓***')  
                        # 发送邮件
                        text = f"换仓平空交易： 交易品种为{data['InstrumentID']}, 交易时间为{trade_df['datetime'].iloc[-1]}, 反手平空的平仓价格为{data['AskPrice1']+param.py}, 交易手数位{param.Lots}"
                        send_mail(text)  
                    #空头开仓
                    if param.pos==0 and 开空条件 and instrument_id in top_two_symbols :
                        #开空
                        # self.insert_order(data['ExchangeID'], data['InstrumentID'], data['BidPrice1']-param.py,param.Lots,b'1',b'0')
                        param.pos=-1
                        param.空头止损价格=trade_df['high'].iloc[-2]
                        param.空头成本价格=data['BidPrice1']
                        param.空头开仓历时=1
                        self.w_log(instrument_id,f'品种：{instrument_id},委托价格: {param.空头成本价格}***开空***')
                        # 发送邮件
                        text = f"空头开仓交易： 交易品种为{data['InstrumentID']}, 交易时间为{trade_df['datetime'].iloc[-1]}, 空头开仓的开仓价格{data['BidPrice1']-param.py}, 交易手数位{param.Lots}"
                        send_mail(text) 
                    #print(trade_df) 
                    #保存OF数据
                    self.save_trade_data(trade_df,instrument_id)
                    #保存bar计数
                    param.cont_df=len(trade_df)
            except queue.Empty:
                # print(f"当前合约队列为空，等待新数据插入。")
                pass
    
    # 将CTP推送的行情数据分发给对应线程队列去执行
    def distribute_tick(self):
        while True:
            if self.status == 0:
                data = None
                while not self.md_queue.empty():
                    data = self.md_queue.get(block=False)
                    instrument_id = data['InstrumentID'].decode()  # 品种代码
                    try:
                        self.queue_dict[instrument_id].put(data, block=False)  # 往对应合约队列中插入行情
                        # print(f"{instrument_id}合约数据插入。")
                    except queue.Full:
                        # 当某个线程阻塞导致对应队列容量超限时抛出异常，不会影响其他合约的信号计算
                        print(f"{instrument_id}合约信号计算阻塞导致对应队列已满，请检查对应代码逻辑后重启。")
            else:
                time.sleep(1)

    def start(self, param_dict):
        threads = []
        self.param_dict = param_dict
        thread1 = threading.Thread(target=横截面计算)
        for symbol in param_dict.keys():
            trade_dfs[symbol] = pd.DataFrame({})
            self.queue_dict[symbol] = queue.Queue(10)   #为每个合约创建一个限制数为10的队列，当计算发生阻塞导致队列达到限制数时会抛出异常
            t = threading.Thread(target=self.cal_sig, args=(self.queue_dict[symbol],)) # 为每个合约单独创建一个线程计算开仓逻辑
            threads.append(t)
            t.start()
        thread1.start()
        self.distribute_tick()
        for t in threads:
            t.join()
        thread1.join()

# 定义横截面计算函数
def 横截面计算():
    global top_two_symbols
    while True:
        if len(截面数据_资金流向)>2:
            goss=1
            # 检查是否有任何品种的更新状态为 False，如果有则直接返回
            for symbol, data in 截面数据_资金流向.items():
                if not data['更新状态'].iloc[-1]:
                    #print(f"品种 {symbol} 的更新状态为 False，跳过计算。")
                    goss=0
                    break
            if goss==1:
                # 继续计算资金净流向
                sorted_items = sorted(截面数据_资金流向.items(), key=lambda item: item[1]['资金净流向'].iloc[-1], reverse=True)
                max_symbol = sorted_items[0][0]
                second_max_symbol = sorted_items[1][0]
                # SAN_max_symbol = sorted_items[2][0]
                top_two_symbols = [max_symbol, second_max_symbol]#,SAN_max_symbol
                
                print(f'最大值和第二大值对应的键: {top_two_symbols}')
                print(f'截面数据_资金流向: {截面数据_资金流向}')
                # 将所有品种的更新状态设置为 False
                for symbol in 截面数据_资金流向:
                    截面数据_资金流向[symbol]['更新状态'] = False
        time.sleep(1)    

# Jerome:tushare库版本
# def get_main_contact_on_time(main_symbol_code):
#     data_str = ''
#     alpha_chars = ''
#     numeric_chars = ''
#     main_code = ''

#     now = datetime.now()
#     if now.hour < 15:
#         data_str = (now - timedelta(days=1)).date().strftime('%Y%m%d')
#     else:
#         data_str = now.date().strftime('%Y%m%d')

#     main_symbol = pro.fut_mapping(ts_code=main_symbol_code, trade_date = data_str).loc[0,'mapping_ts_code'].split('.')[0]
#     exchange_id = pro.fut_mapping(ts_code=main_symbol_code, trade_date = data_str).loc[0,'mapping_ts_code'].split('.')[1]

#     for char in main_symbol:
#         if char.isalpha():
#             alpha_chars += char
#         elif char.isdigit():
#             numeric_chars += char
#     # print("未修改的主连代码：",main_symbol)
#     # print("未修改的主连代码的字母部分：",alpha_chars)
#     # print("未修改的主连代码的数字部分：",numeric_chars)
#     # print("未修改的主连代码对应的交易所：",exchange_id)
#     if exchange_id == 'CFX':
#         main_code = main_symbol
#     elif exchange_id == 'SHF' or exchange_id == 'DCE' or exchange_id == 'GFE' or exchange_id == 'INE':
#         lower_alpha_chars = str.lower(alpha_chars)
#         # print("上期所、大商所、广交所和能源中心主连代码修改为小写的字母部分：",lower_alpha_chars)
#         main_code = lower_alpha_chars + numeric_chars
#     elif exchange_id == 'ZCE':
#         true_numeric_chars = numeric_chars[1:]
#         # print("郑商所主连代码删减数字后数字部分：",true_numeric_chars)
#         main_code = alpha_chars + true_numeric_chars 
#     print("最终使用的主连代码：",main_code) 
#     return main_code  

def get_main_contact_on_time(main_symbol_code,contacts_df):
    main_symbol = contacts_df[contacts_df['品种代码'] == main_symbol_code]['主连代码'].iloc[0]
    print("最终使用的主连代码：",main_symbol)
    return main_symbol

def send_mail(text):
    msg = MIMEMultipart()
    msg["From"]     = sender
    msg["To"]       = ";".join(receivers)
    msg["Subject"]  = subject
    msg.attach(MIMEText(text, "plain", "utf-8"))
    smtp = smtplib.SMTP_SSL(smtp_server, smtp_port)    
    smtp.login(username, password)
    smtp.sendmail(sender, receivers, msg.as_string())
    smtp.quit()

    param_dict[sb_7] = ParamObj(symbol=sb_7, Lots=1, py=6,dj_X=0,delta=500,sum_delta=2000,失衡=3,堆积=3,周期='1min',平_多时间=历时平仓,平_空时间=历时平仓)
    param_dict[sb_8] = ParamObj(symbol=sb_8, Lots=1, py=6,dj_X=0,delta=500,sum_delta=2000,失衡=3,堆积=3,周期='1min',平_多时间=历时平仓,平_空时间=历时平仓)
    param_dict[sb_9] = ParamObj(symbol=sb_9, Lots=1, py=6,dj_X=0,delta=500,sum_delta=2000,失衡=3,堆积=3,周期='1min',平_多时间=历时平仓,平_空时间=历时平仓)
    param_dict[sb_10] = ParamObj(symbol=sb_10, Lots=1, py=6,dj_X=0,delta=500,sum_delta=2000,失衡=3,堆积=3,周期='1min',平_多时间=历时平仓,平_空时间=历时平仓)
if __name__ == '__main__':

    # 所有品种：
    # "a","ag","al","ao","AP","au","b","bb","bc","br","bu",
    # "c","CF","CJ","cs","cu","CY","eb","ec","eg","fb","FG","fu",
    # "hc","i","IC","IF","IH","IM","j","jd","jm","l","lc","lg","lh","lu",
    # "m","MA","ni","nr","OI","p","pb","PF","pg","PK","pp","PR","ps","PX",
    # "rb","RM","rr","RS","ru","SA","sc","SF","SH","si","SM","sn","sp","SR","ss",
    # "T","TA","TF","TL","TS","UR","v","wr","y","zn"
    # 换行后代码如下
    # symbols = [
    #     "a", "ag", "al", "ao", "AP", "au", "b", "bb", "bc", "br", "bu", "c",
    #     "CF", "CJ", "cs", "cu", "CY", "eb", "ec", "eg", "fb", "FG", "fu", "hc",
    #     "i", "IC", "IF", "IH", "IM", "j", "jd", "jm", "l", "lc", "lg", "lh",
    #     "lu", "m", "MA", "ni", "nr", "OI", "p", "pb", "PF", "pg", "PK", "pp",
    #     "PR", "ps", "PX", "rb", "RM", "rr", "RS", "ru", "SA", "sc", "SF",
    #     "SH", "si", "SM", "sn", "sp", "SR", "ss", "T", "TA", "TF", "TL",
    #     "TS", "UR", "v", "wr", "y", "zn"
    # ]
    symbols = contacts_df['品种代码'].tolist()
    for i, symbol in enumerate(symbols, start=1):
        globals()[f'sb_{i}'] = get_main_contact_on_time(symbol, contacts_df)

    #注意：运行前请先安装好algoplus,
    # pip install AlgoPlus
    #http://www.algo.plus/ctp/python/0103001.html


    # 实盘参数字典，需要实盘交易的合约，新建对应的参数对象即可，以下参数仅供测试使用，不作为实盘参考！！！！
    历时平仓=4
    
    param_dict = {}
    for i in range(1, 77):
        symbol = globals()[f'sb_{i}']
        param_dict[symbol] = ParamObj(symbol=symbol, Lots=1, py=6, dj_X=0, delta=500, sum_delta=2000, 失衡=3, 堆积=3, 周期='5min', 平_多时间=历时平仓, 平_空时间=历时平仓)

    #用simnow模拟，不要忘记屏蔽下方实盘的future_account字典
    future_account = get_simulate_account(
        investor_id="135858",  # simnow账户，注意是登录账户的ID，SIMNOW个人首页查看
        password="Zj1234!@#%",  # simnow密码
        server_name="电信1",  # 电信1、电信2、移动、TEST、N视界
        subscribe_list=list(param_dict.keys()),  # 合约列表
    )

    # #实盘用这个，不要忘记屏蔽上方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=list(param_dict.keys()),  # 订阅合约列表
    #     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=(
        param_dict,
        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
    ))
    
    md_process.start()
    trader_process.start()

    md_process.join()
    trader_process.join()
    
  