Browse Source

Merge branch 'master' of http://chenzheshi.myds.me:3000/Daniel/stock

Daniel 1 year ago
parent
commit
a38ed5c64d

+ 1 - 0
.idea/modules.xml

@@ -2,6 +2,7 @@
 <project version="4">
 <project version="4">
   <component name="ProjectModuleManager">
   <component name="ProjectModuleManager">
     <modules>
     <modules>
+      <module fileurl="file://$PROJECT_DIR$/../AI/.idea/AI.iml" filepath="$PROJECT_DIR$/../AI/.idea/AI.iml" />
       <module fileurl="file://$USER_HOME$/PycharmProjects/pythonProject/.idea/pythonProject.iml" filepath="$USER_HOME$/PycharmProjects/pythonProject/.idea/pythonProject.iml" />
       <module fileurl="file://$USER_HOME$/PycharmProjects/pythonProject/.idea/pythonProject.iml" filepath="$USER_HOME$/PycharmProjects/pythonProject/.idea/pythonProject.iml" />
       <module fileurl="file://$USER_HOME$/Library/CloudStorage/OneDrive-个人/个人/python_stocks/quantify01/.idea/quantify01.iml" filepath="$USER_HOME$/Library/CloudStorage/OneDrive-个人/个人/python_stocks/quantify01/.idea/quantify01.iml" />
       <module fileurl="file://$USER_HOME$/Library/CloudStorage/OneDrive-个人/个人/python_stocks/quantify01/.idea/quantify01.iml" filepath="$USER_HOME$/Library/CloudStorage/OneDrive-个人/个人/python_stocks/quantify01/.idea/quantify01.iml" />
       <module fileurl="file://$PROJECT_DIR$/.idea/stock.iml" filepath="$PROJECT_DIR$/.idea/stock.iml" />
       <module fileurl="file://$PROJECT_DIR$/.idea/stock.iml" filepath="$PROJECT_DIR$/.idea/stock.iml" />

+ 1 - 0
.idea/stock.iml

@@ -7,5 +7,6 @@
     <orderEntry type="module" module-name="stocks_to_sql" />
     <orderEntry type="module" module-name="stocks_to_sql" />
     <orderEntry type="module" module-name="quantify01" />
     <orderEntry type="module" module-name="quantify01" />
     <orderEntry type="module" module-name="pythonProject" />
     <orderEntry type="module" module-name="pythonProject" />
+    <orderEntry type="module" module-name="AI" />
   </component>
   </component>
 </module>
 </module>

+ 1 - 1
.idea/vcs.xml

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
 <project version="4">
   <component name="VcsDirectoryMappings">
   <component name="VcsDirectoryMappings">
-    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+    <mapping directory="" vcs="Git" />
   </component>
   </component>
 </project>
 </project>

BIN
QMT/20230516105422482.dmp


+ 414 - 0
QMT/230504_real_time.py

@@ -0,0 +1,414 @@
+# coding:utf-8
+from datetime import datetime as dt
+import os
+import pandas as pd
+from xtquant.xttrader import XtQuantTrader, XtQuantTraderCallback
+from xtquant.xttype import StockAccount
+from xtquant import xtdata, xtconstant
+import time
+from sqlalchemy import create_engine, text
+from jqdatasdk import *
+import pymysql
+import multiprocessing as mp
+import math
+import psutil
+import datetime
+from apscheduler.schedulers.blocking import BlockingScheduler
+import sys
+
+# 指定客户端所在路径
+path = r'c:\\qmt\\userdata_mini'
+# 创建资金账号为 800068 的证券账号对象
+acc = StockAccount('920000207040', 'SECURITY')
+# 生成session id 整数类型 同时运行的策略不能重复
+session_id = 123456
+xt_trader = None
+engine_stock = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/qmt_stocks_whole?charset=utf8',
+                             pool_size=5000, pool_recycle=50, max_overflow=-1)
+auth('18616891214', 'Ea?*7f68nD.dafcW34d!')
+
+
+class MyXtQuantTraderCallback(XtQuantTraderCallback):
+    def on_disconnected(self):
+        """
+        连接断开
+        :return:
+        """
+        print(datetime.datetime.now(), '连接断开回调')
+
+    def on_stock_order(self, order):
+        """
+        委托回报推送
+        :param order: XtOrder对象
+        :return:
+        """
+        print(datetime.datetime.now(), '委托回调', order.order_remark)
+
+    def on_stock_trade(self, trade):
+        """
+        成交变动推送
+        :param trade: XtTrade对象
+        :return:
+        """
+        print(datetime.datetime.now(), '成交回调', trade.order_remark)
+
+    def on_order_error(self, order_error):
+        """
+        委托失败推送
+        :param order_error:XtOrderError 对象
+        :return:
+        """
+        # print("on order_error callback")
+        # print(order_error.order_id, order_error.error_id, order_error.error_msg)
+        print(f"委托报错回调 {order_error.order_remark} {order_error.error_msg}")
+
+    def on_cancel_error(self, cancel_error):
+        """
+        撤单失败推送
+        :param cancel_error: XtCancelError 对象
+        :return:
+        """
+        print(datetime.datetime.now(), sys._getframe().f_code.co_name)
+
+    def on_order_stock_async_response(self, response):
+        """
+        异步下单回报推送
+        :param response: XtOrderResponse 对象
+        :return:
+        """
+        print(f"异步委托回调 {response.order_remark}")
+
+    def on_cancel_order_stock_async_response(self, response):
+        """
+        :param response: XtCancelOrderResponse 对象
+        :return:
+        """
+        print(datetime.datetime.now(), sys._getframe().f_code.co_name)
+
+    def on_account_status(self, status):
+        """
+        :param response: XtAccountStatus 对象
+        :return:
+        """
+        print(datetime.datetime.now(), sys._getframe().f_code.co_name)
+
+
+def run(seq, pid):
+    mor = datetime.datetime.strptime(
+        str(dt.now().date()) + '11:30', '%Y-%m-%d%H:%M')
+    afternoon = datetime.datetime.strptime(
+        str(dt.now().date()) + '15:00', '%Y-%m-%d%H:%M')
+    mor_1 = datetime.datetime.strptime(
+        str(dt.now().date()) + '12:59', '%Y-%m-%d%H:%M')
+    """阻塞线程接收行情回调"""
+    import time
+    client = xtdata.get_client()
+    while True:
+        time.sleep(3)
+        now_date = dt.now()
+        if not client.is_connected():
+            xtdata.unsubscribe_quote(seq)
+            raise Exception('行情服务连接断开')
+        # if mor < dt.now() < mor_1:
+        #     xtdata.unsubscribe_quote(seq)
+        #     print(f'现在时间:{dt.now()},已休市')
+        #     sys.exit()
+        #     break
+        #     return 0
+        elif dt.now() > afternoon:
+            xtdata.unsubscribe_quote(seq)
+            print(f'现在时间:{dt.now()},已收盘')
+            sys.exit()
+            break
+            # return 0
+    return
+
+
+def get_fundamentals(results):
+    return results
+    pass
+
+
+def ma(stock, num, data):
+    global engine_stock
+    try:
+        i = (num - 1) * -1
+        df = pd.read_sql_query(text(
+            'select close_front from `%s_1d`' % stock), engine_stock.connect())
+    except BaseException as e:
+        print(e)
+        return 9999999
+    else:
+        ma_num = (sum(df['close_front'][i:]) + data[stock]['lastPrice']) / num
+        return ma_num
+
+
+def ma_1(stock, num):
+    global engine_stock
+    i = num * -1
+    try:
+        df = pd.read_sql_query(text(
+            'select close_front from `%s_1d`' % stock), engine_stock.connect())
+    except BaseException as e:
+        print(e)
+        return 9999999
+    else:
+        ma_num_1 = df['close_front'][i:].mean()
+        return ma_num_1
+
+
+def his_vol(stock, num):
+    global engine_stock
+    num = num * -1
+    try:
+        df = pd.read_sql_query(text(
+            'select volume_front from `%s_1d`' % stock), engine_stock.connect())
+    except BaseException:
+        return 9999999
+    else:
+        return df['volume_front'].iloc[num]
+
+
+def ma_judge(data, list_judge, rate, results):
+    # print(f'这个ma_judge的PID为:{os.getpid()},本轮计算:{len(list_judge)}个股')
+    for stock in list_judge:
+        current_price, open_price = data[stock]['lastPrice'], data[stock]['open']
+        MA5, MA10, MA20, MA30, MA60, MA120 = ma(stock, 5, data), ma(stock, 10, data), ma(stock, 20, data), ma(stock, 30,
+                                                                                                              data), \
+            ma(stock, 60, data), ma(stock, 120, data)
+        MA5_1 = ma_1(stock, 5)
+        # print(i, current_price, open_price, MA5, MA10, MA20, MA5_1)
+        # 入交易池标准:阳线\大于MA5\MA5向上\MA20<MA10\离120线有距离
+        if (current_price > open_price) & (current_price > MA5) & (MA5 > MA5_1) & (current_price < MA5 * 1.05) \
+                & (current_price > MA120 or current_price < MA120 * rate):
+            if his_vol(stock, -1) > his_vol(stock, -2):
+                results.append(stock.replace('SH', 'XSHG').replace('SZ', 'XSHE'))
+
+
+def sell_trader(data):
+    # print('卖出函数:', dt.now())
+    positions = xt_trader.query_stock_positions(acc)
+    positions_dict = {positions[x].stock_code: positions[x].can_use_volume for x in range(0, len(positions))}
+    print(
+        f'目前持仓总数为:{len([positions[x].stock_code for x in range(0, len(positions)) if positions[x].volume != 0])}')
+
+    for stock, can_use_volume in positions_dict.items():
+        if stock in data and can_use_volume != 0:
+            current_price = data[stock]['lastPrice']
+            open_price = data[stock]['open']
+            MA5 = ma(stock, 5, data)
+            MA5_1 = ma_1(stock, 5)
+            df = pd.read_sql_query(text(
+                'select close_front, high_front from `%s_1d`' % stock), engine_stock.connect())
+            print(f"{data[stock]['time']}, {stock},持仓量为{can_use_volume}当前价:{current_price},开盘价:{open_price},"
+                  f"MA5:{MA5},昨日MA5:{MA5_1},开始判断:")
+            if current_price == xtdata.get_instrument_detail(stock).get('UpStopPrice') \
+                    or (df['close_front'].iloc[-1] == df['high_front'].iloc[-1]
+                        and df['close_front'].iloc[-1] / df['close_front'].iloc[-2] > 1.08):
+                print(f"{stock}涨停或昨日涨幅超过8%,持股观察!{data[stock]['time']}")
+                continue
+            elif current_price < MA5 or MA5 < MA5_1:
+                print('卖出信号!!!!!!', stock, current_price)
+                order_id = xt_trader.order_stock(acc, stock, xtconstant.STOCK_SELL, can_use_volume,
+                                                 xtconstant.LATEST_PRICE, 0, 'MA5策略', '低于MA5趋势向下')
+                print('价格:', current_price, open_price, MA5, MA5_1, '低于MA5趋势向下')
+                print(order_id, stock, can_use_volume)
+            elif current_price > MA5 * 1.07:
+                print('盈利乖离率超7%!!!!!!', stock, current_price)
+                order_id = xt_trader.order_stock(acc, stock, xtconstant.STOCK_SELL, can_use_volume,
+                                                 xtconstant.LATEST_PRICE, 0, 'MA5策略', '盈利乖离率超7%')
+                print('价格:', current_price, open_price, MA5, MA5_1, '盈利乖离率超7%')
+                print(order_id, stock, can_use_volume)
+        else:
+            # print(f'本轮没有持仓股票信息!')
+            pass
+        engine_stock.dispose()
+
+
+def buy_trader(data):
+    # print('买入函数:', dt.now(), f'接受到{len(data.keys())}个个股')
+    results = mp.Manager().list()
+    mp_list = []
+    engine_hlfx_pool = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/hlfx_pool?charset=utf8',
+                                     pool_size=4000, pool_recycle=50, max_overflow=-1)
+
+    try:
+        stock_pool = pd.read_sql_query(
+            text('select value from `%s` order by `index` desc limit 10' % '1d'), engine_hlfx_pool.connect())
+        stock_pool = stock_pool.iloc[0, 0].split(",")
+        stock_pool.sort()
+        print('stock_pool', len(stock_pool))
+
+    except BaseException as e:
+        print(e)
+
+    if len(stock_pool) != 0:
+        list_judge = list(set(data.keys()) & set(stock_pool))
+        print(f'本轮有{len(data.keys())}条个股信息,而list_judge有:{len(list_judge)}')
+    else:
+        print(f'stock_pool为{len(stock_pool)}个')
+    step = math.ceil(len(list_judge) / 4)
+    rate = 0.8
+    if len(list_judge) != 0:
+        print(f'list_judge:{list_judge}')
+        for i in range(0, len(list_judge), step):
+            p = mp.Process(target=ma_judge, args=(data, list_judge[i:i + step], rate, results))
+            mp_list.append(p)
+            p.start()
+        for j in mp_list:
+            j.join()
+    results = list(set(results))
+
+    # 选择板块
+    if len(results) != 0:
+        print(f'进入板块选择{results}')
+        # 基本面过滤
+        results = get_fundamentals(results)
+        num_industry = get_industry(results)
+        industry_list = []
+        for key in num_industry.values():
+            for key2 in key.values():
+                industry_list.append(key2['industry_name'])
+        industry_list = pd.value_counts(industry_list)
+        # 最热集中的n个板块
+        max_industry_list = list(industry_list[0:2].index)
+        results_industry = []
+        for key, value in num_industry.items():
+            for key2 in value.values():
+                if key2['industry_name'] in max_industry_list:
+                    results_industry.append(key)
+        results_industry = ','.join(set(results_industry))
+        print('1d', '\n', results_industry)
+
+        db_pool = pymysql.connect(host='localhost',
+                                  user='root',
+                                  port=3307,
+                                  password='r6kEwqWU9!v3',
+                                  database='hlfx_pool')
+        cursor_pool = db_pool.cursor()
+        sql = "INSERT INTO MA5_%s (date,value) VALUES('%s','%s')" % ('1d', dt.now().strftime('%Y-%m-%d %H:%M:%S'),
+                                                                     results_industry)
+        cursor_pool.execute(sql)
+        db_pool.commit()
+
+        # print(len(results_industry), results_industry)
+        print(dt.now(), '数据库数据已赋值!')
+        cursor_pool.close()
+        db_pool.close()
+
+        # 取值交易
+        keep_stocks = results_industry.split(",")
+        new_keep_stock = [stock.replace('XSHG', 'SH').replace('XSHE', 'SZ') for stock in keep_stocks]
+        print(f'{dt.now()},new_keep_stock is:{len(new_keep_stock)}')
+
+        if len(new_keep_stock) != 0:
+            # 进入购买程序
+            max_pos = 7
+            for stock in new_keep_stock:
+                positions = xt_trader.query_stock_positions(acc)
+
+                asset = xt_trader.query_stock_asset(acc)
+                cash = asset.cash
+                positions_dict = {positions[x].stock_code: positions[x].volume for x in range(0, len(positions)) if
+                                  positions[x].volume > 0}
+                print(f'判断{stock}:cash={cash},持仓数量为{len(positions_dict)}')
+                current_price = data[stock]['lastPrice']
+                current_high = data[stock]['high']
+                if stock not in positions_dict:
+                    if len(positions_dict) < max_pos and current_price > 9 \
+                            and current_price > (current_high * 0.98):
+                        if 5000 > cash:
+                            i = 1
+                        else:
+                            i = 2
+                        volume = int((cash / i / current_price) // 100 * 100)
+                        print('买入信号!!!!!!', stock, volume, current_price)
+                        order_id = xt_trader.order_stock(acc, stock, xtconstant.STOCK_BUY, volume,
+                                                         xtconstant.LATEST_PRICE,
+                                                         current_price, 'MA5策略', 'MA5趋势向上')
+                        print(order_id)
+                    else:
+                        print(f'Cash只有:{cash} 或者 现有持仓{len(positions_dict)} 超过了{max_pos}')
+                else:
+                    print(f'{stock}已持仓!')
+    engine_hlfx_pool.dispose()
+    print('一轮结束了,现在时间是:', dt.now())
+
+
+def trader(data):
+    print(f'本轮订阅{len(data)}')
+    # print(f'xt_trader = {xt_trader},{session_id}')
+    # print(len(xt_trader.query_stock_positions(acc)))
+    # 卖出判断
+    sell_trader(data)
+    # 买入条件
+    buy_trader(data)
+
+
+def bridge():
+    global session_id, xt_trader
+    pid = os.getpid()
+    connect_result = -1
+    subscribe_result = -1
+
+    while True:
+        if connect_result != 0 or subscribe_result != 0:
+            session_id = int(time.time())
+            xt_trader = XtQuantTrader(path, session_id)
+            # 创建交易回调类对象,并声明接收回调
+            callback = MyXtQuantTraderCallback()
+            xt_trader.register_callback(callback)
+            # 启动交易线程
+            xt_trader.start()
+            # 建立交易连接,返回0表示连接成功
+            connect_result = xt_trader.connect()
+            print('建立交易连接,返回0表示连接成功', connect_result)
+            # 对交易回调进行订阅,订阅后可以收到交易主推,返回0表示订阅成功
+            subscribe_result = xt_trader.subscribe(acc)
+            print('对交易回调进行订阅,订阅后可以收到交易主推,返回0表示订阅成功', subscribe_result)
+            # 建立交易连接,返回0表示连接成功
+            connect_result = xt_trader.connect()
+            print('建立交易连接,返回0表示连接成功', connect_result)
+            # 对交易回调进行订阅,订阅后可以收到交易主推,返回0表示订阅成功
+            subscribe_result = xt_trader.subscribe(acc)
+            print('对交易回调进行订阅,订阅后可以收到交易主推,返回0表示订阅成功', subscribe_result)
+            time.sleep(3)
+        else:
+            break
+    print(f'MyPid is {os.getpid()}, now is {dt.now()},开盘了,session_id = {session_id}, \n')
+    positions = xt_trader.query_stock_positions(acc)
+    positions_dict = {positions[x].stock_code: positions[x].can_use_volume for x in range(0, len(positions))}
+    print(f'今日可卖出个股总数:{len([value for value in positions_dict.values() if value != 0])}')
+    stocks = xtdata.get_stock_list_in_sector('沪深A股')
+    seq = xtdata.subscribe_whole_quote(stocks, callback=trader)
+    run(seq, pid)
+
+
+def job_func():
+    print(f"Job started at {dt.now()}")
+    # 创建子进程
+    p = mp.Process(target=bridge)
+    # 启动子进程
+    p.start()
+    # 等待子进程结束
+    p.join()
+    print(f"Job finished at {dt.now()}")
+
+
+if __name__ == '__main__':
+    mp.freeze_support()
+    # print('cpu_count =', mp.cpu_count())
+    pus = psutil.Process()
+    pus.cpu_affinity([12, 13, 14, 15])
+
+    # job_func()
+
+    scheduler = BlockingScheduler()
+    scheduler.add_job(func=job_func, trigger='cron', day_of_week='0-4', hour='09', minute='40',
+                      timezone="Asia/Shanghai", max_instances=5)
+    # scheduler.add_job(func=job_func, trigger='cron', day_of_week='0-4', hour='12', minute='35',
+    #                   timezone="Asia/Shanghai")
+    try:
+        scheduler.start()
+    except (KeyboardInterrupt, SystemExit):
+        pass

+ 415 - 0
QMT/5m_data_whole.py

@@ -0,0 +1,415 @@
+from xtquant import xtdata
+from datetime import datetime as dt
+import pandas as pd
+import math
+from sqlalchemy import create_engine, text
+import multiprocessing as mp
+import os
+from apscheduler.schedulers.blocking import BlockingScheduler
+import traceback
+import psutil
+import pymysql
+import talib as ta
+import numpy as np
+
+
+pd.set_option('display.max_columns', None) # 设置显示最大行
+
+
+path = 'C:\\qmt\\userdata_mini'
+
+field = ['time', 'open', 'close', 'high', 'low', 'volume', 'amount']
+cpu_count = mp.cpu_count()
+
+
+def err_call_back(err):
+    print(f'问题在这里~ error:{str(err)}')
+    traceback.print_exc()
+
+
+def err_call_back(err):
+    print(f'出错啦~ error:{str(err)}')
+    traceback.print_exc()
+
+
+def myself_kdj(df):
+    low_list = df['low_back'].rolling(9, min_periods=9).min()
+    low_list.fillna(value=df['low_back'].expanding().min(), inplace=True)
+    high_list = df['high_back'].rolling(9, min_periods=9).max()
+    high_list.fillna(value=df['high_back'].expanding().max(), inplace=True)
+    rsv = (df['close_back'] - low_list) / (high_list - low_list) * 100
+    df['k'] = pd.DataFrame(rsv).ewm(com=2).mean()
+    df['d'] = df['k'].ewm(com=2).mean()
+    df['j'] = 3 * df['k'] - 2 * df['d']
+    return df
+
+
+# macd指标
+def get_macd_data(data, short=0, long1=0, mid=0):
+    if short == 0:
+        short = 12
+    if long1 == 0:
+        long1 = 26
+    if mid == 0:
+        mid = 9
+    data['sema'] = pd.Series(data['close_back']).ewm(span=short).mean()
+    data['lema'] = pd.Series(data['close_back']).ewm(span=long1).mean()
+    data.fillna(0, inplace=True)
+    data['dif'] = data['sema'] - data['lema']
+    data['dea'] = pd.Series(data['dif']).ewm(span=mid).mean()
+    data['macd'] = 2 * (data['dif'] - data['dea'])
+    data.fillna(0, inplace=True)
+    # return data[['dif', 'dea', 'macd']]
+
+
+# rsi指标
+def get_ris(data):
+    data["rsi_6"] = ta.RSI(data['close_back'], timeperiod=6)
+    data["rsi_12"] = ta.RSI(data['close_back'], timeperiod=12)
+    data["rsi_24"] = ta.RSI(data['close_back'], timeperiod=24)
+
+
+def get_bias(data):
+    # 计算方法:
+    # bias指标
+    # N期BIAS=(当日收盘价-N期平均收盘价)/N期平均收盘价*100%
+    data['bias_6'] = (data['close_back'] - data['close_back'].rolling(6, min_periods=1).mean()) / \
+                     data['close_back'].rolling(6, min_periods=1).mean() * 100
+    data['bias_12'] = (data['close_back'] - data['close_back'].rolling(12, min_periods=1).mean()) / \
+                      data['close_back'].rolling(12, min_periods=1).mean() * 100
+    data['bias_24'] = (data['close_back'] - data['close_back'].rolling(24, min_periods=1).mean()) / \
+                      data['close_back'].rolling(24, min_periods=1).mean() * 100
+    data['bias_6'] = round(data['bias_6'], 2)
+    data['bias_12'] = round(data['bias_12'], 2)
+    data['bias_24'] = round(data['bias_24'], 2)
+
+
+def get_wilr(data):
+    # 威廉指标
+    # 建议用talib库的WILLR方法,亲测有用
+    data['willr'] = ta.WILLR(data['high_back'], data['low_back'], data['close_back'], timeperiod=14)
+
+
+def get_hlfx(data):
+    Trading_signals = 0
+    data_temp = data[['time', 'open_back', 'close_back', 'high_back', 'low_back', 'dif', 'dea', 'macd']]
+    data_temp.columns = ['time', 'open', 'close', 'high', 'low', 'dif', 'dea', 'macd']
+    df_day = pd.DataFrame(columns=['time', 'open', 'close', 'high', 'low', 'volume', 'money', 'HL'])
+    # 先处理去包含
+    for i in data_temp.index:
+        if i == 0 or i == 1:
+            df_day = pd.concat([df_day, data_temp.iloc[[i]]], ignore_index=True)
+        # 不包含
+        elif (df_day.iloc[-1, 3] > data_temp.loc[i, 'high']
+              and df_day.iloc[-1, 4] > data_temp.loc[i, 'low']) \
+                or (df_day.iloc[-1, 3] < data_temp.loc[i, 'high']
+                    and df_day.iloc[-1, 4] < data_temp.loc[i, 'low']):
+            df_day = pd.concat([df_day, data_temp.loc[[i]]], ignore_index=True)
+        # 包含
+        else:
+            # 左高,下降
+            if df_day.iloc[-2, 3] > df_day.iloc[-1, 3]:
+                df_day.iloc[-1, 3] = min(df_day.iloc[-1, 3], data_temp.loc[i, 'high'])
+                df_day.iloc[-1, 4] = min(df_day.iloc[-1, 4], data_temp.loc[i, 'low'])
+            else:
+                # 右高,上升
+                df_day.iloc[-1, 3] = max(df_day.iloc[-1, 3], data_temp.loc[i, 'high'])
+                df_day.iloc[-1, 4] = max(df_day.iloc[-1, 4], data_temp.loc[i, 'low'])
+    # print('111', df_day, data_temp)
+
+    if len(df_day.index) > 2:
+        # 寻找顶底分型
+        for x in range(2, len(df_day.index)):
+            m = x - 1
+            # 底
+            # 符合底分型形态,且第2、3根k线是阳线
+            if ((df_day.loc[x, 'high'] > df_day.loc[x - 1, 'high']) and
+                (df_day.loc[x - 2, 'high'] > df_day.loc[x - 1, 'high'])):
+                # and df_day.loc[x, 'close'] > df_day.loc[x, 'open'] and \
+                #     df_day.loc[x - 1, 'close'] > df_day.loc[x - 1, 'open']:
+
+                df_day.loc[x, 'HL'] = 'L*'
+
+                while m:
+                    if df_day.loc[m, 'HL'] in ['H', 'HH', 'H*']:
+                        if (x - m) > 3:
+                            # 成笔——>L
+                            df_day.loc[x, 'HL'] = 'L'
+                            # 产生信号,进入hlfx_pool
+                            if x == len(df_day.index) - 1:
+                                Trading_signals = 1
+                        else:
+                            # 不成笔 次级别中枢,保持L* 修订原H为H*
+                            df_day.loc[m, 'HL'] = 'H*'
+                        break
+
+                    elif df_day.loc[m, 'HL'] in ['L', 'LL', 'L*']:
+                        if df_day.loc[m - 1, 'low'] > df_day.loc[x - 1, 'low']:
+                            # 前一个为底更高,且中间不存在更低的底
+                            df_day.loc[x, 'HL'] = 'L'
+                            df_day.loc[m, 'HL'] = '-'
+
+                            # 产生信号,进入hlfx_pool
+                            if x == len(df_day.index) - 1:
+                                Trading_signals = 1
+
+                            # 获得MACD,判断MACD判断背驰
+                            x_macd_dif, x_macd_dea, x_macd_macd = data_temp.loc[x, 'dif'], data_temp.loc[x, 'dea'], \
+                            data_temp.loc[x, 'macd']
+                            m_macd_dif, m_macd_dea, m_macd_macd = data_temp.loc[m, 'dif'], data_temp.loc[m, 'dea'], \
+                            data_temp.loc[m, 'macd']
+
+                            # MACD底背驰
+                            if m_macd_dif < x_macd_dif:
+                                # 次级别背驰底->LL
+                                df_day.loc[x, 'HL'] = 'LL'
+                            break
+                        else:
+                            # 前底更低,本底无效
+                            df_day.loc[x, 'HL'] = '-'
+                            break
+                    m = m - 1
+                    if m == 0:
+                        df_day.loc[x, 'HL'] = 'L'
+
+            # 顶
+            elif ((df_day.loc[x, 'high'] < df_day.loc[x - 1, 'high']) and (
+                    df_day.loc[x - 2, 'high'] < df_day.loc[x - 1, 'high'])):
+
+                df_day.loc[x, 'HL'] = 'H*'
+                while m:
+                    if df_day.loc[m, 'HL'] in ['L', 'LL', 'L*']:
+                        if x - m > 3:
+                            # 成笔->H
+                            df_day.loc[x, 'HL'] = 'H'
+                            # 产生信号,进入hlfx_pool
+                            if x == len(df_day.index) - 1:
+                                Trading_signals = 2
+                        else:
+                            # 不成笔 次级别中枢,保持H* 修订原L为L*
+                            df_day.loc[m, 'HL'] = 'L*'
+                        break
+
+                    elif df_day.loc[m, 'HL'] in ['H', 'HH', 'H*']:
+                        if df_day.loc[x - 1, 'high'] > df_day.loc[m - 1, 'high']:
+                            # 前一个为顶,且中间存在不包含 or 更高的顶
+                            df_day.loc[x, 'HL'] = 'H'
+                            df_day.loc[m, 'HL'] = '-'
+                            # 产生信号,进入hlfx_pool
+                            if x == len(df_day.index) - 1:
+                                Trading_signals = 2
+
+                            # 获得MACD,判断MACD判断背驰
+                            x_macd_dif, x_macd_dea, x_macd_macd = data_temp.loc[x, 'dif'], data_temp.loc[x, 'dea'], \
+                            data_temp.loc[x, 'macd']
+                            m_macd_dif, m_macd_dea, m_macd_macd = data_temp.loc[m, 'dif'], data_temp.loc[m, 'dea'], \
+                            data_temp.loc[m, 'macd']
+
+                            # MACD顶背驰
+                            if x_macd_dif < m_macd_dif:
+                                # 次级别背驰底->HH
+                                df_day.loc[x, 'HL'] = 'HH'
+                            break
+                        else:
+                            # 前顶更高,本顶无效
+                            df_day.loc[x, 'HL'] = '-'
+                            break
+                    m = m - 1
+                    if m == 0:
+                        df_day.loc[x, 'HL'] = 'H'
+
+            else:
+                df_day.loc[x, 'HL'] = '-'
+    df_temp = df_day[['time', 'HL']]
+
+    return df_temp, Trading_signals
+
+
+def tech_anal(stocks, hlfx_pool, hlfx_pool_daily, err_list):
+    print(f'{dt.now()}开始循环计算! MyPid is {os.getpid()},池子长度为{len(stocks)}')
+    m = 0
+
+    for stock in stocks:
+        engine = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/5m_stocks_whole?charset=utf8',
+                               pool_size=1, pool_recycle=7200, max_overflow=1000, pool_timeout=60)
+        engine_tech = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/5m_stocks_tech?charset=utf8',
+                                    pool_size=1, pool_recycle=3600, max_overflow=1000, pool_timeout=60)
+        # print(stock)
+        try:
+            df = pd.read_sql_table('%s_5m' % stock, con=engine.connect())
+            df.dropna(axis=0, how='any')
+            engine.dispose()
+        except BaseException:
+            print(f'{stock}读取有问题')
+            traceback.print_exc()
+            pass
+        else:
+            if len(df) != 0:
+                try:
+                    get_macd_data(df)
+                    get_ris(df)
+                    get_bias(df)
+                    get_wilr(df)
+                    df_temp, T_signals = get_hlfx(df)
+                    df = pd.merge(df, df_temp, on='time', how='left')
+                    df['HL'].fillna(value='-', inplace=True)
+                    df = df.reset_index(drop=True)
+                    # print(stock, '\n', df[['open_front', 'HL']])
+                    df = df.replace([np.inf, -np.inf], np.nan)
+                    df.to_sql('%s_5m' % stock, con=engine_tech, index=False, if_exists='replace')
+                    engine_tech.dispose()
+                # with engine.connect() as con:
+                #     con.execute("ALTER TABLE `%s_5m` ADD PRIMARY KEY (`time`);" % stock)
+                except BaseException as e:
+                    print(f'{stock}存储有问题', e)
+                    traceback.print_exc()
+                    err_list.append(stock)
+                    pass
+                else:
+                    # print(f"{stock} 成功!")
+                    m += 1
+            else:
+                err_list.append(stock)
+                print(f'{stock}数据为空')
+
+            if stock in hlfx_pool and T_signals == 2:
+                hlfx_pool.remove(stock)
+            elif stock not in hlfx_pool and T_signals == 1:
+                hlfx_pool.append(stock)
+                hlfx_pool_daily.append(stock)
+
+    print(f'Pid:{os.getpid()}已经完工了,应处理{len(stocks)},共计算{m}支个股')
+
+
+def ind():
+    sttime = dt.now()
+
+    stocks = xtdata.get_stock_list_in_sector('沪深A股')
+    print(len(stocks))
+    stocks.sort()
+
+    err_list = mp.Manager().list()
+    fre = '5m'
+    engine_hlfx_pool = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/hlfx_pool?charset=utf8',
+                                     pool_size=1, pool_recycle=3600, max_overflow=1000, pool_timeout=60)
+    hlfx_pool = mp.Manager().list()
+    hlfx_pool_daily = mp.Manager().list()
+    hlfx_pool.extend(pd.read_sql_query(
+        text("select value from %s" % fre), engine_hlfx_pool.connect()).iloc[-1, 0].split(","))
+
+    # pool = mp.Pool(processes=int(mp.cpu_count()))
+    # step = math.ceil(len(stocks) / mp.cpu_count())
+    pool = mp.Pool(processes=12)
+    step = math.ceil(len(stocks) / 12)
+    # step = 10000
+    # tech_anal(stocks, hlfx_pool)
+    for i in range(0, len(stocks), step):
+        pool.apply_async(func=tech_anal, args=(stocks[i:i + step], hlfx_pool, hlfx_pool_daily, err_list,),
+                         error_callback=err_call_back)
+    pool.close()
+    pool.join()
+    engine_hlfx_pool.dispose()
+
+    print(f'当日信号:{len(hlfx_pool_daily)},持续检测为:{len(hlfx_pool)}')
+    print(len(err_list), err_list)
+
+    results_list = ','.join(set(hlfx_pool))
+    results_list_daily = ','.join(set(hlfx_pool_daily))
+
+    # 存档入库
+    db_pool = pymysql.connect(host='localhost',
+                              user='root',
+                              port=3307,
+                              password='r6kEwqWU9!v3',
+                              database='hlfx_pool')
+    cursor_pool = db_pool.cursor()
+    sql = "INSERT INTO %s (date,value) VALUES('%s','%s')" % (fre, dt.now().strftime('%Y-%m-%d %H:%M:%S'), results_list)
+    cursor_pool.execute(sql)
+    db_pool.commit()
+
+    # 存档入库daily_5m
+    db_pool2 = pymysql.connect(host='localhost',
+                               user='root',
+                               port=3307,
+                               password='r6kEwqWU9!v3',
+                               database='hlfx_pool')
+    cursor_pool2 = db_pool2.cursor()
+    sql2 = "INSERT INTO daily_%s (date,value) VALUES('%s','%s')" % (fre, dt.now().strftime('%Y-%m-%d %H:%M:%S'),
+                                                                    results_list_daily)
+    cursor_pool2.execute(sql2)
+    db_pool2.commit()
+
+    edtime = dt.now()
+    print(edtime - sttime)
+
+
+def to_sql(stock_list):
+    print(f'{dt.now()}开始循环入库! MyPid is {os.getpid()}')
+    m = 0
+    for stock in stock_list:
+        eng_w = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/5m_stocks_whole?charset=utf8',
+                              pool_recycle=3600, pool_pre_ping=True, pool_size=1)
+        # 后复权数据
+        data_back = xtdata.get_market_data(field, [stock], '5m', end_time='', count=-1, dividend_type='back')
+        df_back = pd.concat([data_back[i].loc[stock].T for i in ['time', 'open', 'high', 'low', 'close', 'volume',
+                                                                 'amount']], axis=1)
+        df_back.columns = ['time', 'open_back', 'high_back', 'low_back', 'close_back', 'volume_back', 'amount_back']
+        df_back['time'] = df_back['time'].apply(lambda x: dt.fromtimestamp(x / 1000.0))
+        df_back.reset_index(drop=True, inplace=True)
+
+        # 前复权数据
+        data_front = xtdata.get_market_data(field, [stock], '5m', end_time='', count=-1, dividend_type='front')
+        df_front = pd.concat([data_front[i].loc[stock].T for i in ['time', 'open', 'high', 'low', 'close', 'volume',
+                                                                   'amount']], axis=1)
+        df_front.columns = ['time', 'open_front', 'high_front', 'low_front', 'close_front', 'volume_front',
+                            'amount_front']
+        df_front['time'] = df_front['time'].apply(lambda x: dt.fromtimestamp(x / 1000.0))
+        df = pd.merge_asof(df_back, df_front, 'time')
+        # print(df)
+        try:
+            # eng_w.connect().execute(text("truncate table `%s_5m`" % stock))
+            df.to_sql('%s_5m' % stock, con=eng_w, index=False, if_exists='replace', chunksize=5000)
+        except BaseException as e:
+            print(stock, e)
+            pass
+        else:
+            m += 1
+
+        eng_w.dispose()
+    print(f'Pid:{os.getpid()}已经完工了.应入库{len(stock_list)},共入库{m}支个股')
+
+
+def download_data():
+    stock_list = xtdata.get_stock_list_in_sector('沪深A股')
+    stock_list.sort()
+    print(dt.now(), '开始下载!')
+    # xtdata.download_history_data2(stock_list=stock_list, period='5m', start_time='', end_time='')
+    print(dt.now(), '下载完成,准备入库!')
+    # step = math.ceil(len(stock_list) / mp.cpu_count())
+    # pool = mp.Pool(processes=mp.cpu_count())
+    # pool = mp.Pool(processes=12)
+    # step = math.ceil(len(stock_list) / 12)
+    # for i in range(0, len(stock_list), step):
+    #     pool.apply_async(func=to_sql, args=(stock_list[i:i+step],), error_callback=err_call_back)
+    # pool.close()
+    # pool.join()
+    ind()
+
+    print(f'今日数据下载完毕 {dt.now()}')
+
+
+if __name__ == '__main__':
+    field = ['time', 'open', 'close', 'high', 'low', 'volume', 'amount']
+    cpu_count = mp.cpu_count()
+    pus = psutil.Process()
+    pus.cpu_affinity([8, 9, 10, 11, 16, 17, 18, 19, 20, 21, 22, 23])
+
+    download_data()
+
+    # scheduler = BlockingScheduler()
+    # scheduler.add_job(func=download_data, trigger='cron', day_of_week='0-4', hour='23', minute='05',
+    #                   timezone="Asia/Shanghai", max_instances=10)
+    # try:
+    #     scheduler.start()
+    # except (KeyboardInterrupt, SystemExit):
+    #     pass

+ 61 - 0
QMT/LSTM_1.py

@@ -0,0 +1,61 @@
+import pandas as pd
+import numpy as np
+from sklearn.preprocessing import MinMaxScaler
+from keras.models import Sequential
+from keras.layers import Dense, LSTM
+from ta.volatility import BollingerBands
+from ta.trend import MACD
+from ta.trend import EMAIndicator
+from ta.volume import MFIIndicator
+from sqlalchemy import create_engine
+
+# 加载数据
+engine_tech = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/qmt_stocks_tech?charset=utf8')
+df = pd.read_sql_table('600000.SH_1d', con=engine_tech)
+
+
+df = df[['open_back', 'high_back', 'low_back', 'close_back', 'volume_back', 'close_back', 'macd', 'willr', 'volume_back', 'dif', 'dea', 'rsi_6', 'rsi_12', 'rsi_24']].values
+
+# df = df[~np.isnan(df).any(axis=1), :]
+
+# 归一化
+scaler = MinMaxScaler(feature_range=(0, 1))
+scaled_data = scaler.fit_transform(df)
+print(len(df), len(scaled_data))
+
+# 构造训练数据
+lookback = 90
+target_days = 30
+
+x_train = []
+y_train = []
+for i in range(lookback, len(df) - target_days):
+    x_train.append(scaled_data[i - lookback:i])
+    y_train.append(scaled_data[i:i + target_days, 0])
+
+x_train, y_train = np.array(x_train), np.array(y_train)
+print('11111111111111111111', x_train.shape, y_train.shape)
+
+
+# 构建模型
+model = Sequential()
+model.add(LSTM(units=50, return_sequences=True, input_shape=(x_train.shape[1], x_train.shape[2])))
+model.add(LSTM(units=50, return_sequences=True))
+model.add(LSTM(units=50))
+model.add(Dense(units=30))
+
+model.compile(optimizer='adam', loss='mean_squared_error')
+
+model.fit(x_train, y_train, epochs=10, batch_size=32)
+
+# 预测未来30天走势
+test_data = scaled_data[-lookback:]
+test_data = np.expand_dims(test_data, axis=0)
+print(test_data.shape)
+predictions = model.predict(test_data)
+
+# 将归一化的预测数据转换为原始数据
+predictions = scaler.inverse_transform(predictions)
+
+# 打印预测结果
+print(predictions)

+ 376 - 8
QMT/chongxie_run.py

@@ -1,10 +1,16 @@
+# coding:utf-8
 from xtquant.xttrader import XtQuantTrader, XtQuantTraderCallback
 from xtquant.xttrader import XtQuantTrader, XtQuantTraderCallback
 from xtquant.xttype import StockAccount
 from xtquant.xttype import StockAccount
 from xtquant import xtdata, xtconstant
 from xtquant import xtdata, xtconstant
 from datetime import datetime as dt
 from datetime import datetime as dt
+import pandas as pd
+import time
+import datetime
+import sys
+import os
 
 
-
-
+pd.set_option('display.max_columns', None) # 设置显示最大行
+"""
 def run():
 def run():
     '''阻塞线程接收行情回调'''
     '''阻塞线程接收行情回调'''
     import time
     import time
@@ -12,15 +18,377 @@ def run():
     while True:
     while True:
         time.sleep(3)
         time.sleep(3)
         now_date = dt.now()
         now_date = dt.now()
-        if not client.is_connected() or dt.now() > now_date.replace(hour=11, minute=30, second=0):
+        if not client.is_connected() :
             raise Exception('行情服务连接断开')
             raise Exception('行情服务连接断开')
             break
             break
     return
     return
 
 
+
 def trader(data):
 def trader(data):
-    print(dt.now(), len(data.keys()), data.keys())
+    # print('callback',os.getpid())
+    print(f'{dt.now()},len={len(data.keys())}')
+    print(data)
+
+
+# stocks = xtdata.get_stock_list_in_sector("沪深债券")
+# print(len(stocks))
+stocks = ['110043.SH', '110044.SH', '128075.SZ', '128079.SZ', '113017.SH', '128119.SZ']
+# # stocks = ['110055.SZ', '110061.SZ']
+stock_code = '127045.SZ'
+# seq2 = xtdata.subscribe_quote(stock_code, period='tick', start_time='20230101', end_time='20230407', count=10000, callback=trader)
+# # print(seq2)
+# seq = xtdata.subscribe_whole_quote(['沪深债券'], callback=trader)
+sss = xtdata.subscribe_whole_quote(stocks, callback=trader)
+# aaa = xtdata.subscribe_quote('128130.SZ', period='tick', start_time='', end_time='', count=0, callback=trader)
+#
+xtdata.run()
+exit()
+"""
+
+
+class MyXtQuantTraderCallback(XtQuantTraderCallback):
+    def on_disconnected(self):
+        """
+        连接断开
+        :return:
+        """
+        print(datetime.datetime.now(), '连接断开回调')
+
+    def on_stock_order(self, order):
+        """
+        委托回报推送
+        :param order: XtOrder对象
+        :return:
+        """
+        print(datetime.datetime.now(), '委托回调', order.order_remark)
+
+    def on_stock_trade(self, trade):
+        """
+        成交变动推送
+        :param trade: XtTrade对象
+        :return:
+        """
+        print(datetime.datetime.now(), '成交回调', trade.order_remark)
+
+    def on_order_error(self, order_error):
+        """
+        委托失败推送
+        :param order_error:XtOrderError 对象
+        :return:
+        """
+        # print("on order_error callback")
+        # print(order_error.order_id, order_error.error_id, order_error.error_msg)
+        print(f"委托报错回调 {order_error.order_remark} {order_error.error_msg}")
+
+    def on_cancel_error(self, cancel_error):
+        """
+        撤单失败推送
+        :param cancel_error: XtCancelError 对象
+        :return:
+        """
+        print(datetime.datetime.now(), sys._getframe().f_code.co_name)
+
+    def on_order_stock_async_response(self, response):
+        """
+        异步下单回报推送
+        :param response: XtOrderResponse 对象
+        :return:
+        """
+        print(f"异步委托回调 {response.order_remark}")
+
+    def on_cancel_order_stock_async_response(self, response):
+        """
+        :param response: XtCancelOrderResponse 对象
+        :return:
+        """
+        print(datetime.datetime.now(), sys._getframe().f_code.co_name)
+
+    def on_account_status(self, status):
+        """
+        :param response: XtAccountStatus 对象
+        :return:
+        """
+        print(datetime.datetime.now(), sys._getframe().f_code.co_name)
+
+
+def get_tick(code, start_time, end_time, period='tick'):
+    from xtquant import xtdata
+
+    xtdata.download_history_data(code, period=period, start_time=start_time, end_time=end_time)
+    data = xtdata.get_local_data(field_list=[], stock_code=[code], period=period)
+    result_list = data[code]
+    df = pd.DataFrame(result_list)
+
+    df['time'] = df['time'].apply(lambda x: datetime.datetime.fromtimestamp(x / 1000.0))
+    return df.iloc[-20:].loc[:, ['time', 'lastPrice', 'open', 'high','low','amount', 'volume']]
+    # return df.iloc[-20:,:]
+
+
+def process_timestamp(df, filename):
+    df = df.set_index('time_str')
+    result = df.resample('3S').first().ffill()
+    # result = result[(result.index >= '2022-07-20 09:30') & (result.index <= '2022-07-20 15:00')]
+    result = result.reset_index()
+    # result.to_csv(filename + '.csv')
+    print(result)
+
+
+def get_macd_data(data, short=0, long1=0, mid=0):
+    if short == 0:
+        short = 12
+    if long1 == 0:
+        long1 = 26
+    if mid == 0:
+        mid = 9
+    data['sema'] = pd.Series(data['close']).ewm(span=short).mean()
+    data['lema'] = pd.Series(data['close']).ewm(span=long1).mean()
+    data.fillna(0, inplace=True)
+    data['dif'] = data['sema'] - data['lema']
+    data['dea'] = pd.Series(data['dif']).ewm(span=mid).mean()
+    data['macd'] = 2 * (data['dif'] - data['dea'])
+    data.fillna(0, inplace=True)
+    return data
+
+
+def get_hlfx(data):
+    Trading_signals = 0
+    data_temp = data[['time', 'open', 'close', 'high', 'low', 'dif', 'dea', 'macd']]
+    data_temp.columns = ['time', 'open', 'close', 'high', 'low', 'dif', 'dea', 'macd']
+    df_day = pd.DataFrame(columns=['time', 'open', 'close', 'high', 'low', 'volume', 'money', 'HL'])
+    # 先处理去包含
+    for i in data_temp.index:
+        if i == 0 or i == 1:
+            df_day = pd.concat([df_day, data_temp.iloc[[i]]], ignore_index=True)
+        # 不包含
+        elif (df_day.iloc[-1, 3] > data_temp.loc[i, 'high']
+              and df_day.iloc[-1, 4] > data_temp.loc[i, 'low']) \
+                or (df_day.iloc[-1, 3] < data_temp.loc[i, 'high']
+                    and df_day.iloc[-1, 4] < data_temp.loc[i, 'low']):
+            df_day = pd.concat([df_day, data_temp.loc[[i]]], ignore_index=True)
+        # 包含
+        else:
+            # 左高,下降
+            if df_day.iloc[-2, 3] > df_day.iloc[-1, 3]:
+                df_day.iloc[-1, 3] = min(df_day.iloc[-1, 3], data_temp.loc[i, 'high'])
+                df_day.iloc[-1, 4] = min(df_day.iloc[-1, 4], data_temp.loc[i, 'low'])
+            else:
+                # 右高,上升
+                df_day.iloc[-1, 3] = max(df_day.iloc[-1, 3], data_temp.loc[i, 'high'])
+                df_day.iloc[-1, 4] = max(df_day.iloc[-1, 4], data_temp.loc[i, 'low'])
+    # print('111', df_day, data_temp)
+
+    if len(df_day.index) > 2:
+        # 寻找顶底分型
+        for x in range(2, len(df_day.index)):
+            m = x - 1
+            # 底
+            # 符合底分型形态,且第2、3根k线是阳线
+            if ((df_day.loc[x, 'high'] > df_day.loc[x - 1, 'high']) and
+                (df_day.loc[x - 2, 'high'] > df_day.loc[x - 1, 'high'])) and \
+                    df_day.loc[x, 'close'] > df_day.loc[x, 'open'] and \
+                    df_day.loc[x - 1, 'close'] > df_day.loc[x - 1, 'open']:
+
+                df_day.loc[x, 'HL'] = 'L*'
+                while m:
+                    if df_day.loc[m, 'HL'] in ['H', 'HH', 'H*']:
+                        if (x - m) > 3:
+                            # 成笔——>L
+                            df_day.loc[x, 'HL'] = 'L'
+                            # 产生信号,进入hlfx_pool
+                            if x == len(df_day.index) - 1:
+                                Trading_signals = 1
+
+                    elif df_day.loc[m, 'HL'] == 'L':
+                        if df_day.loc[m - 1, 'low'] > df_day.loc[x - 1, 'low']:
+                            # 前一个为底更高,且中间不存在更低的底
+                            df_day.loc[x, 'HL'] = 'L'
+
+                            # 产生信号,进入hlfx_pool
+                            if x == len(df_day.index) - 1:
+                                Trading_signals = 1
+
+                            # 获得MACD,判断MACD判断背驰
+                            x_macd_dif, x_macd_dea, x_macd_macd = data_temp.loc[x, 'dif'], data_temp.loc[x, 'dea'], \
+                            data_temp.loc[x, 'macd']
+                            m_macd_dif, m_macd_dea, m_macd_macd = data_temp.loc[m, 'dif'], data_temp.loc[m, 'dea'], \
+                            data_temp.loc[m, 'macd']
+
+                            # MACD底背驰
+                            if m_macd_dif < x_macd_dif:
+                                # 背驰底->LL
+                                df_day.loc[x, 'HL'] = 'LL'
+                            break
+                        break
+                    m = m - 1
+                    if m == 0:
+                        df_day.loc[x, 'HL'] = 'L'
+
+            # 顶
+            elif ((df_day.loc[x, 'high'] < df_day.loc[x - 1, 'high']) and (
+                    df_day.loc[x - 2, 'high'] < df_day.loc[x - 1, 'high'])):
+
+                df_day.loc[x, 'HL'] = 'H*'
+                while m:
+                    if df_day.loc[m, 'HL'] in ['L', 'LL', 'L*']:
+                        if x - m > 3:
+                            # 成笔->H
+                            df_day.loc[x, 'HL'] = 'H'
+                            # 产生信号,进入hlfx_pool
+                            if x == len(df_day.index) - 1:
+                                Trading_signals = 2
+
+                    elif df_day.loc[m, 'HL'] == 'H':
+                        if df_day.loc[x - 1, 'high'] > df_day.loc[m - 1, 'high']:
+                            # 前一个为顶,且中间存在不包含 or 更高的顶
+                            df_day.loc[x, 'HL'] = 'H'
+                            # 产生信号,进入hlfx_pool
+                            if x == len(df_day.index) - 1:
+                                Trading_signals = 2
+
+                            # 获得MACD,判断MACD判断背驰
+                            x_macd_dif, x_macd_dea, x_macd_macd = data_temp.loc[x, 'dif'], data_temp.loc[x, 'dea'], \
+                            data_temp.loc[x, 'macd']
+                            m_macd_dif, m_macd_dea, m_macd_macd = data_temp.loc[m, 'dif'], data_temp.loc[m, 'dea'], \
+                            data_temp.loc[m, 'macd']
+
+                            # MACD顶背驰
+                            if x_macd_dif < m_macd_dif:
+                                df_day.loc[x, 'HL'] = 'HH'
+                            break
+                        break
+                    m = m - 1
+                    if m == 0:
+                        df_day.loc[x, 'HL'] = 'H'
+
+            else:
+                df_day.loc[x, 'HL'] = '-'
+    df_temp = df_day[['time', 'HL']]
+
+    return df_temp, Trading_signals
+
+
+def ma(df, num):
+    i = -1 * (5 + num)
+    try:
+        if i == -5:
+            ma_num = sum(df['close'][i:])/5
+        else:
+            ma_num = (sum(df['close'][i:(i+5)]))/5
+        # print(df['close'][i:(i+5)])
+    except:
+        return 9999999
+    else:
+        return ma_num
+
+
+def cont(data):
+    # print(dt.now())
+    code = '127045.SZ'
+    dd = xtdata.get_market_data(field_list=[], stock_list=[code], period='tick', start_time='20230101', end_time='',
+                                count=-1, dividend_type='none', fill_data=True)
+    # print(dt.now(), type(dd), dd[code].shape)
+    # print(dd[code]['time'][-10:-1], '\n', dd[code]['lastPrice'][-10:-1], '\n', dd[code]['open'][-10:-1], '\n', dd[code]['high'][-10:-1])
+    # print(dd[code], '\n'*2)
+    dic = {'time': dd[code]['time'],
+           'open': dd[code]['open'],
+           'close': dd[code]['lastPrice'],
+           'high': dd[code]['high'],
+           'low': dd[code]['low']}
+    df_day = pd.DataFrame(dic)
+    df_day['time'] = df_day['time'].apply(lambda x: dt.fromtimestamp(x / 1000.0))
+    ma_now = ma(df_day, 0)
+    ma_1 = ma(df_day, 1)
+    ma_2 = ma(df_day, 2)
+    ma_3 = ma(df_day,3)
+    # print(ma_now,ma_1,ma_2)
+
+    positions = xt_trader.query_stock_positions(acc)
+    positions_dict = {positions[x].stock_code: positions[x].can_use_volume for x in range(0, len(positions))}
+    # print(positions_dict)
+
+    if code in positions_dict and positions_dict[code] != 0:
+        if df_day['close'].iloc[-1] < ma_now or ma_now < ma_1:
+            order_id = xt_trader.order_stock(acc, code, xtconstant.STOCK_SELL, positions_dict[code],
+                                             xtconstant.LATEST_PRICE, 0, '可转债', '滞涨')
+            print(f'可转债卖出_{order_id},成交价格:{xtconstant.LATEST_PRICE}')
+    # if df_day['close'].iloc[-1] > ma_now > ma_1 and ma_1 < ma_2 <= ma_3 and df_day['close'].iloc[-2] < ma_1:
+    #     print('buy:',  df_day['time'].iloc[-1], df_day['close'].iloc[-1], ma_now)
+    #     order_id = xt_trader.order_stock(acc, code, xtconstant.STOCK_BUY, 10, xtconstant.LATEST_PRICE,
+    #                                      0, '可转债', '跳多MA5')
+    #     print(f'可转债Buy——{order_id},成交价格:{xtconstant.LATEST_PRICE}')
+    if df_day['close'].iloc[-1] > df_day['close'].iloc[-2] and df_day['close'].iloc[-4] >df_day['close'].iloc[-3] > df_day['close'].iloc[-2]:
+        print('buy:', df_day['time'].iloc[-1], df_day['close'].iloc[-1], ma_now)
+        order_id = xt_trader.order_stock(acc, code, xtconstant.STOCK_BUY, 10, xtconstant.LATEST_PRICE, 0, '可转债', 'tick底分型')
+        print(f'可转债Buy——{order_id},成交价格:{xtconstant.LATEST_PRICE}')
+    # df_day = get_macd_data(df_day)
+    # df_day, Trading_signals= get_hlfx(df_day)
+    # print(df_day)
+    if dic ==1:
+        pass
+    elif dic ==1:
+        pass
+
+
+def dump_single_code_tick():
+    # 导出单个转债的tick数据
+    code='127045'
+    start_date = '20230101'
+    end_date = '202304010'
+
+    post_fix = 'SZ' if code.startswith('12') else 'SH'
+    code = '{}.{}'.format(code,post_fix)
+    print(code)
+    filename = '{}'.format(code)
+    df = get_tick(code, start_date, end_date)
+    print(df)
+
+
+if __name__ == '__main__':
+    # 指定客户端所在路径
+    path = r'c:\\qmt\\userdata_mini'
+    # 生成session id 整数类型 同时运行的策略不能重复
+    session_id = int(time.time())
+    xt_trader = XtQuantTrader(path, session_id)
+    # 创建资金账号为 800068 的证券账号对象
+    acc = StockAccount('920000207040', 'SECURITY')
+    # 创建交易回调类对象,并声明接收回调
+    callback = MyXtQuantTraderCallback()
+    xt_trader.register_callback(callback)
+    # 启动交易线程
+    xt_trader.start()
+    # 建立交易连接,返回0表示连接成功
+    connect_result = xt_trader.connect()
+    print('建立交易连接,返回0表示连接成功', connect_result)
+    # 对交易回调进行订阅,订阅后可以收到交易主推,返回0表示订阅成功
+    subscribe_result = xt_trader.subscribe(acc)
+    print('对交易回调进行订阅,订阅后可以收到交易主推,返回0表示订阅成功', subscribe_result)
+
+    code = '127045.SZ'
+    st = dt.now()
+    stocks = xtdata.get_stock_list_in_sector('沪深A股')
+    xtdata.subscribe_quote(code, 'tick', start_time='', end_time='', count=1000, callback=cont)
+    # xtdata.subscribe_whole_quote(stocks,callback=cont)
+    # dd = xtdata.get_market_data(field_list=[], stock_list=[code], period='tick', start_time='20230101', end_time='',
+    #                             count=-1,
+    #                             dividend_type='none', fill_data=True)
+
+    # print(positions_dict[code])
+    # print(type(dd), type(dd[code]), type(dd[code][-1]), dd[code], dd)
+    # print(dd[code]['lastPrice'])
+    # dd[code]['time'] = dd[code]['time'].apply(lambda x: dt.fromtimestamp(x / 1000.0))
+    # print(type(dd[code]['time']), dd[code]['time'])
+    # print('________','\n')
+    # print(type(list(dd[code]['time'])))
+    # print('________')
+    # print(dd[code])
+    xtdata.run()
+    # dump_single_code_tick()
+
+    et = dt.now()
+    print(et-st)
+
+
+
+
+
 
 
-# stocks = stocks = xtdata.get_stock_list_in_sector('沪深A股')
-stocks = ['000001.SZ', '600000.SH', '300389.SZ', '001229.SZ', '600674.SH', '000895.SZ']
-xtdata.subscribe_whole_quote(stocks, callback=trader)
-run()

+ 23 - 3
QMT/demo.py

@@ -4,6 +4,8 @@ from xtquant import xtdata
 from xtquant.xttrader import XtQuantTrader, XtQuantTraderCallback
 from xtquant.xttrader import XtQuantTrader, XtQuantTraderCallback
 from xtquant.xttype import StockAccount
 from xtquant.xttype import StockAccount
 from xtquant import xtconstant
 from xtquant import xtconstant
+from sqlalchemy import create_engine
+import pandas as pd
 
 
 #定义一个类 创建类的实例 作为状态的容器
 #定义一个类 创建类的实例 作为状态的容器
 class _a():
 class _a():
@@ -99,6 +101,17 @@ class MyXtQuantTraderCallback(XtQuantTraderCallback):
 
 
 
 
 if __name__ == '__main__':
 if __name__ == '__main__':
+    engine = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/qmt_stocks_tech?charset=utf8')
+    df = pd.read_sql_table('601155.SH_1d', engine)
+    df = df[df['HL'] != '-']
+    print(df)
+    df.to_csv(f"C:\Daniel\策略\601155.csv", index=True, encoding='utf_8_sig',
+              mode='w')
+
+
+
+
+    exit()
     print("start")
     print("start")
     #指定客户端所在路径
     #指定客户端所在路径
     path = r'c:\\qmt\\userdata_mini'
     path = r'c:\\qmt\\userdata_mini'
@@ -118,9 +131,16 @@ if __name__ == '__main__':
     # 对交易回调进行订阅,订阅后可以收到交易主推,返回0表示订阅成功
     # 对交易回调进行订阅,订阅后可以收到交易主推,返回0表示订阅成功
     subscribe_result = xt_trader.subscribe(acc)
     subscribe_result = xt_trader.subscribe(acc)
     print('对交易回调进行订阅,订阅后可以收到交易主推,返回0表示订阅成功', subscribe_result)
     print('对交易回调进行订阅,订阅后可以收到交易主推,返回0表示订阅成功', subscribe_result)
-    # asset = xt_trader.query_stock_asset(acc)
-    # cash = asset.cash
-    # print(cash)
+    asset = xt_trader.query_stock_asset(acc)
+    cash = asset.cash
+    positions = xt_trader.query_stock_positions(acc)
+
+    print(cash, positions)
+    # xt_trader.run_forever()
+    print('run over')
+    if '600362.SH' == positions[0].stock_code:
+        print('aaa')
+    exit()
     # xtdata.subscribe_whole_quote(["SH", "SZ"], callback=f)
     # xtdata.subscribe_whole_quote(["SH", "SZ"], callback=f)
     xtdata.run()
     xtdata.run()
 
 

+ 18 - 9
QMT/download_data_whole.py

@@ -2,11 +2,12 @@ from xtquant import xtdata
 from datetime import datetime as dt
 from datetime import datetime as dt
 import pandas as pd
 import pandas as pd
 import math
 import math
-from sqlalchemy import create_engine
+from sqlalchemy import create_engine, text
 import multiprocessing as mp
 import multiprocessing as mp
 import os
 import os
 from apscheduler.schedulers.blocking import BlockingScheduler
 from apscheduler.schedulers.blocking import BlockingScheduler
 import traceback
 import traceback
+import psutil
 
 
 
 
 pd.set_option('display.max_columns', None) # 设置显示最大行
 pd.set_option('display.max_columns', None) # 设置显示最大行
@@ -16,7 +17,8 @@ path = 'C:\\qmt\\userdata_mini'
 
 
 field = ['time', 'open', 'close', 'high', 'low', 'volume', 'amount']
 field = ['time', 'open', 'close', 'high', 'low', 'volume', 'amount']
 cpu_count = mp.cpu_count()
 cpu_count = mp.cpu_count()
-eng_w = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/qmt_stocks_whole?charset=utf8')
+
+
 
 
 
 
 def err_call_back(err):
 def err_call_back(err):
@@ -28,6 +30,8 @@ def to_sql(stock_list):
     print(f'{dt.now()}开始循环入库! MyPid is {os.getpid()}')
     print(f'{dt.now()}开始循环入库! MyPid is {os.getpid()}')
     m = 0
     m = 0
     for stock in stock_list:
     for stock in stock_list:
+        eng_w = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/qmt_stocks_whole?charset=utf8',
+                              pool_recycle=3600, pool_pre_ping=True, pool_size=1)
         # 后复权数据
         # 后复权数据
         data_back = xtdata.get_market_data(field, [stock], '1d', end_time='', count=-1, dividend_type='back')
         data_back = xtdata.get_market_data(field, [stock], '1d', end_time='', count=-1, dividend_type='back')
         df_back = pd.concat([data_back[i].loc[stock].T for i in ['time', 'open', 'high', 'low', 'close', 'volume',
         df_back = pd.concat([data_back[i].loc[stock].T for i in ['time', 'open', 'high', 'low', 'close', 'volume',
@@ -46,12 +50,15 @@ def to_sql(stock_list):
         df = pd.merge_asof(df_back, df_front, 'time')
         df = pd.merge_asof(df_back, df_front, 'time')
         # print(df)
         # print(df)
         try:
         try:
-            df.to_sql('%s_1d' % stock, con=eng_w, index=True, if_exists='replace')
-        except BaseException:
-            print(stock)
+            # eng_w.connect().execute(text("truncate table `%s_1d`" % stock))
+            df.to_sql('%s_1d' % stock, con=eng_w, index=False, if_exists='replace', chunksize=20000)
+        except BaseException as e:
+            print(stock, e)
             pass
             pass
         else:
         else:
             m += 1
             m += 1
+
+        eng_w.dispose()
     print(f'Pid:{os.getpid()}已经完工了.应入库{len(stock_list)},共入库{m}支个股')
     print(f'Pid:{os.getpid()}已经完工了.应入库{len(stock_list)},共入库{m}支个股')
 
 
 
 
@@ -63,6 +70,8 @@ def download_data():
     print(dt.now(), '下载完成,准备入库!')
     print(dt.now(), '下载完成,准备入库!')
     step = math.ceil(len(stock_list) / mp.cpu_count())
     step = math.ceil(len(stock_list) / mp.cpu_count())
     pool = mp.Pool(processes=mp.cpu_count())
     pool = mp.Pool(processes=mp.cpu_count())
+    # pool = mp.Pool(processes=8)
+    # step = math.ceil(len(stock_list) / 8)
     for i in range(0, len(stock_list), step):
     for i in range(0, len(stock_list), step):
         pool.apply_async(func=to_sql, args=(stock_list[i:i+step],), error_callback=err_call_back)
         pool.apply_async(func=to_sql, args=(stock_list[i:i+step],), error_callback=err_call_back)
     pool.close()
     pool.close()
@@ -71,17 +80,17 @@ def download_data():
     print(f'今日数据下载完毕 {dt.now()}')
     print(f'今日数据下载完毕 {dt.now()}')
 
 
 
 
-
 if __name__ == '__main__':
 if __name__ == '__main__':
     field = ['time', 'open', 'close', 'high', 'low', 'volume', 'amount']
     field = ['time', 'open', 'close', 'high', 'low', 'volume', 'amount']
     cpu_count = mp.cpu_count()
     cpu_count = mp.cpu_count()
-
+    pus = psutil.Process()
+    # pus.cpu_affinity([12, 13, 14, 15, 16, 17, 18, 19])
 
 
     # download_data()
     # download_data()
 
 
     scheduler = BlockingScheduler()
     scheduler = BlockingScheduler()
-    scheduler.add_job(func=download_data, trigger='cron', day_of_week='0-4', hour='15', minute='40',
-                      timezone="Asia/Shanghai")
+    scheduler.add_job(func=download_data, trigger='cron', day_of_week='0-4', hour='20', minute='05',
+                      timezone="Asia/Shanghai", max_instances=10)
     try:
     try:
         scheduler.start()
         scheduler.start()
     except (KeyboardInterrupt, SystemExit):
     except (KeyboardInterrupt, SystemExit):

+ 63 - 23
QMT/qmt_get_indicators.py

@@ -4,7 +4,7 @@ import numpy as np
 import os
 import os
 import pandas as pd
 import pandas as pd
 import time
 import time
-from sqlalchemy import create_engine
+from sqlalchemy import create_engine, text
 from jqdatasdk import *
 from jqdatasdk import *
 import pymysql
 import pymysql
 import multiprocessing as mp
 import multiprocessing as mp
@@ -13,9 +13,10 @@ import talib as ta
 from xtquant import xtdata
 from xtquant import xtdata
 import os
 import os
 import traceback
 import traceback
+from apscheduler.schedulers.blocking import BlockingScheduler
+import psutil
 
 
 pd.set_option('display.max_columns', None)  # 设置显示最大行
 pd.set_option('display.max_columns', None)  # 设置显示最大行
-engine = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/qmt_stocks_whole?charset=utf8')
 
 
 
 
 def err_call_back(err):
 def err_call_back(err):
@@ -54,7 +55,6 @@ def get_macd_data(data, short=0, long1=0, mid=0):
 
 
 
 
 # rsi指标
 # rsi指标
-# 建议用talib库的RSI方法,亲测有用
 def get_ris(data):
 def get_ris(data):
     data["rsi_6"] = ta.RSI(data['close_back'], timeperiod=6)
     data["rsi_6"] = ta.RSI(data['close_back'], timeperiod=6)
     data["rsi_12"] = ta.RSI(data['close_back'], timeperiod=12)
     data["rsi_12"] = ta.RSI(data['close_back'], timeperiod=12)
@@ -116,11 +116,12 @@ def get_hlfx(data):
             # 底
             # 底
             # 符合底分型形态,且第2、3根k线是阳线
             # 符合底分型形态,且第2、3根k线是阳线
             if ((df_day.loc[x, 'high'] > df_day.loc[x - 1, 'high']) and
             if ((df_day.loc[x, 'high'] > df_day.loc[x - 1, 'high']) and
-                (df_day.loc[x - 2, 'high'] > df_day.loc[x - 1, 'high'])) and \
-                    df_day.loc[x, 'close'] > df_day.loc[x, 'open'] and \
-                    df_day.loc[x - 1, 'close'] > df_day.loc[x - 1, 'open']:
+                (df_day.loc[x - 2, 'high'] > df_day.loc[x - 1, 'high'])):
+                # and df_day.loc[x, 'close'] > df_day.loc[x, 'open'] and \
+                #     df_day.loc[x - 1, 'close'] > df_day.loc[x - 1, 'open']:
 
 
                 df_day.loc[x, 'HL'] = 'L*'
                 df_day.loc[x, 'HL'] = 'L*'
+
                 while m:
                 while m:
                     if df_day.loc[m, 'HL'] in ['H', 'HH', 'H*']:
                     if df_day.loc[m, 'HL'] in ['H', 'HH', 'H*']:
                         if (x - m) > 3:
                         if (x - m) > 3:
@@ -129,11 +130,16 @@ def get_hlfx(data):
                             # 产生信号,进入hlfx_pool
                             # 产生信号,进入hlfx_pool
                             if x == len(df_day.index) - 1:
                             if x == len(df_day.index) - 1:
                                 Trading_signals = 1
                                 Trading_signals = 1
+                        else:
+                            # 不成笔 次级别中枢,保持L* 修订原H为H*
+                            df_day.loc[m, 'HL'] = 'H*'
+                        break
 
 
-                    elif df_day.loc[m, 'HL'] == 'L':
+                    elif df_day.loc[m, 'HL'] in ['L', 'LL', 'L*']:
                         if df_day.loc[m - 1, 'low'] > df_day.loc[x - 1, 'low']:
                         if df_day.loc[m - 1, 'low'] > df_day.loc[x - 1, 'low']:
                             # 前一个为底更高,且中间不存在更低的底
                             # 前一个为底更高,且中间不存在更低的底
                             df_day.loc[x, 'HL'] = 'L'
                             df_day.loc[x, 'HL'] = 'L'
+                            df_day.loc[m, 'HL'] = '-'
 
 
                             # 产生信号,进入hlfx_pool
                             # 产生信号,进入hlfx_pool
                             if x == len(df_day.index) - 1:
                             if x == len(df_day.index) - 1:
@@ -147,10 +153,13 @@ def get_hlfx(data):
 
 
                             # MACD底背驰
                             # MACD底背驰
                             if m_macd_dif < x_macd_dif:
                             if m_macd_dif < x_macd_dif:
-                                # 背驰底->LL
+                                # 次级别背驰底->LL
                                 df_day.loc[x, 'HL'] = 'LL'
                                 df_day.loc[x, 'HL'] = 'LL'
                             break
                             break
-                        break
+                        else:
+                            # 前底更低,本底无效
+                            df_day.loc[x, 'HL'] = '-'
+                            break
                     m = m - 1
                     m = m - 1
                     if m == 0:
                     if m == 0:
                         df_day.loc[x, 'HL'] = 'L'
                         df_day.loc[x, 'HL'] = 'L'
@@ -168,11 +177,16 @@ def get_hlfx(data):
                             # 产生信号,进入hlfx_pool
                             # 产生信号,进入hlfx_pool
                             if x == len(df_day.index) - 1:
                             if x == len(df_day.index) - 1:
                                 Trading_signals = 2
                                 Trading_signals = 2
+                        else:
+                            # 不成笔 次级别中枢,保持H* 修订原L为L*
+                            df_day.loc[m, 'HL'] = 'L*'
+                        break
 
 
-                    elif df_day.loc[m, 'HL'] == 'H':
+                    elif df_day.loc[m, 'HL'] in ['H', 'HH', 'H*']:
                         if df_day.loc[x - 1, 'high'] > df_day.loc[m - 1, 'high']:
                         if df_day.loc[x - 1, 'high'] > df_day.loc[m - 1, 'high']:
                             # 前一个为顶,且中间存在不包含 or 更高的顶
                             # 前一个为顶,且中间存在不包含 or 更高的顶
                             df_day.loc[x, 'HL'] = 'H'
                             df_day.loc[x, 'HL'] = 'H'
+                            df_day.loc[m, 'HL'] = '-'
                             # 产生信号,进入hlfx_pool
                             # 产生信号,进入hlfx_pool
                             if x == len(df_day.index) - 1:
                             if x == len(df_day.index) - 1:
                                 Trading_signals = 2
                                 Trading_signals = 2
@@ -185,9 +199,13 @@ def get_hlfx(data):
 
 
                             # MACD顶背驰
                             # MACD顶背驰
                             if x_macd_dif < m_macd_dif:
                             if x_macd_dif < m_macd_dif:
+                                # 次级别背驰底->HH
                                 df_day.loc[x, 'HL'] = 'HH'
                                 df_day.loc[x, 'HL'] = 'HH'
                             break
                             break
-                        break
+                        else:
+                            # 前顶更高,本顶无效
+                            df_day.loc[x, 'HL'] = '-'
+                            break
                     m = m - 1
                     m = m - 1
                     if m == 0:
                     if m == 0:
                         df_day.loc[x, 'HL'] = 'H'
                         df_day.loc[x, 'HL'] = 'H'
@@ -201,15 +219,18 @@ def get_hlfx(data):
 
 
 def tech_anal(stocks, hlfx_pool, hlfx_pool_daily, err_list):
 def tech_anal(stocks, hlfx_pool, hlfx_pool_daily, err_list):
     print(f'{dt.now()}开始循环计算! MyPid is {os.getpid()},池子长度为{len(stocks)}')
     print(f'{dt.now()}开始循环计算! MyPid is {os.getpid()},池子长度为{len(stocks)}')
-
-    engine_tech = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/qmt_stocks_tech?charset=utf8')
     m = 0
     m = 0
 
 
     for stock in stocks:
     for stock in stocks:
+        engine = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/qmt_stocks_whole?charset=utf8',
+                               pool_size=1, pool_recycle=7200, max_overflow=1000, pool_timeout=60)
+        engine_tech = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/qmt_stocks_tech?charset=utf8',
+                                    pool_size=1, pool_recycle=3600, max_overflow=1000, pool_timeout=60)
         # print(stock)
         # print(stock)
         try:
         try:
-            df = pd.read_sql_table('%s_1d' % stock, con=engine)
+            df = pd.read_sql_table('%s_1d' % stock, con=engine.connect())
             df.dropna(axis=0, how='any')
             df.dropna(axis=0, how='any')
+            engine.dispose()
         except BaseException:
         except BaseException:
             print(f'{stock}读取有问题')
             print(f'{stock}读取有问题')
             traceback.print_exc()
             traceback.print_exc()
@@ -228,6 +249,7 @@ def tech_anal(stocks, hlfx_pool, hlfx_pool_daily, err_list):
                     # print(stock, '\n', df[['open_front', 'HL']])
                     # print(stock, '\n', df[['open_front', 'HL']])
                     df = df.replace([np.inf, -np.inf], np.nan)
                     df = df.replace([np.inf, -np.inf], np.nan)
                     df.to_sql('%s_1d' % stock, con=engine_tech, index=False, if_exists='replace')
                     df.to_sql('%s_1d' % stock, con=engine_tech, index=False, if_exists='replace')
+                    engine_tech.dispose()
                 # with engine.connect() as con:
                 # with engine.connect() as con:
                 #     con.execute("ALTER TABLE `%s_1d` ADD PRIMARY KEY (`time`);" % stock)
                 #     con.execute("ALTER TABLE `%s_1d` ADD PRIMARY KEY (`time`);" % stock)
                 except BaseException:
                 except BaseException:
@@ -248,10 +270,12 @@ def tech_anal(stocks, hlfx_pool, hlfx_pool_daily, err_list):
                 hlfx_pool.append(stock)
                 hlfx_pool.append(stock)
                 hlfx_pool_daily.append(stock)
                 hlfx_pool_daily.append(stock)
 
 
+
+
     print(f'Pid:{os.getpid()}已经完工了,应处理{len(stocks)},共计算{m}支个股')
     print(f'Pid:{os.getpid()}已经完工了,应处理{len(stocks)},共计算{m}支个股')
 
 
 
 
-if __name__ == '__main__':
+def ind():
     sttime = dt.now()
     sttime = dt.now()
 
 
     stocks = xtdata.get_stock_list_in_sector('沪深A股')
     stocks = xtdata.get_stock_list_in_sector('沪深A股')
@@ -260,25 +284,26 @@ if __name__ == '__main__':
 
 
     err_list = mp.Manager().list()
     err_list = mp.Manager().list()
     fre = '1d'
     fre = '1d'
-    engine_hlfx_pool = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/hlfx_pool?charset=utf8')
+    engine_hlfx_pool = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/hlfx_pool?charset=utf8',
+                                     pool_size=1, pool_recycle=3600, max_overflow=1000, pool_timeout=60)
     hlfx_pool = mp.Manager().list()
     hlfx_pool = mp.Manager().list()
     hlfx_pool_daily = mp.Manager().list()
     hlfx_pool_daily = mp.Manager().list()
     hlfx_pool.extend(pd.read_sql_query(
     hlfx_pool.extend(pd.read_sql_query(
-        'select value from `%s`' % fre, engine_hlfx_pool).iloc[-1, 0].split(","))
+        text("select value from %s" % fre), engine_hlfx_pool.connect()).iloc[-1, 0].split(","))
 
 
-    pool = mp.Pool(processes=mp.cpu_count())
+    pool = mp.Pool(processes=int(mp.cpu_count()))
     step = math.ceil(len(stocks) / mp.cpu_count())
     step = math.ceil(len(stocks) / mp.cpu_count())
+    # pool = mp.Pool(processes=16)
+    # step = math.ceil(len(stocks) / 16)
     # step = 10000
     # step = 10000
-    x = 1
     # tech_anal(stocks, hlfx_pool)
     # tech_anal(stocks, hlfx_pool)
     for i in range(0, len(stocks), step):
     for i in range(0, len(stocks), step):
-        print(x)
         pool.apply_async(func=tech_anal, args=(stocks[i:i + step], hlfx_pool, hlfx_pool_daily, err_list,),
         pool.apply_async(func=tech_anal, args=(stocks[i:i + step], hlfx_pool, hlfx_pool_daily, err_list,),
                          error_callback=err_call_back)
                          error_callback=err_call_back)
-        x += 1
     time.sleep(5)
     time.sleep(5)
     pool.close()
     pool.close()
     pool.join()
     pool.join()
+    engine_hlfx_pool.dispose()
 
 
     print(f'当日信号:{len(hlfx_pool_daily)},持续检测为:{len(hlfx_pool)}')
     print(f'当日信号:{len(hlfx_pool_daily)},持续检测为:{len(hlfx_pool)}')
     print(len(err_list), err_list)
     print(len(err_list), err_list)
@@ -303,11 +328,26 @@ if __name__ == '__main__':
                                port=3307,
                                port=3307,
                                password='r6kEwqWU9!v3',
                                password='r6kEwqWU9!v3',
                                database='hlfx_pool')
                                database='hlfx_pool')
-    cursor_pool2 = db_pool.cursor()
+    cursor_pool2 = db_pool2.cursor()
     sql2 = "INSERT INTO daily_%s (date,value) VALUES('%s','%s')" % (fre, dt.now().strftime('%Y-%m-%d %H:%M:%S'),
     sql2 = "INSERT INTO daily_%s (date,value) VALUES('%s','%s')" % (fre, dt.now().strftime('%Y-%m-%d %H:%M:%S'),
                                                                     results_list_daily)
                                                                     results_list_daily)
     cursor_pool2.execute(sql2)
     cursor_pool2.execute(sql2)
     db_pool2.commit()
     db_pool2.commit()
-    edtime = dt.now()
 
 
+    edtime = dt.now()
     print(edtime - sttime)
     print(edtime - sttime)
+
+
+if __name__ == '__main__':
+    pus = psutil.Process()
+    # pus.cpu_affinity([12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23])
+
+    # ind()
+
+    scheduler = BlockingScheduler()
+    scheduler.add_job(func=ind, trigger='cron', day_of_week='0-4', hour='20', minute='30',
+                      timezone="Asia/Shanghai", max_instances=10)
+    try:
+        scheduler.start()
+    except (KeyboardInterrupt, SystemExit):
+        pass

+ 170 - 128
QMT/qmt_real_hlfx.py

@@ -2,7 +2,7 @@
 # from jqdatasdk import *
 # from jqdatasdk import *
 import pandas as pd
 import pandas as pd
 import pymysql
 import pymysql
-from sqlalchemy import create_engine
+from sqlalchemy import create_engine, text
 import threading
 import threading
 from datetime import datetime as dt
 from datetime import datetime as dt
 import datetime
 import datetime
@@ -17,9 +17,10 @@ import os
 import psutil
 import psutil
 import traceback
 import traceback
 from apscheduler.schedulers.blocking import BlockingScheduler
 from apscheduler.schedulers.blocking import BlockingScheduler
+import sys
+import gc
 
 
-#原始版本
-
+# 原始版本
 # auth('18616891214', 'Ea?*7f68nD.dafcW34d!')
 # auth('18616891214', 'Ea?*7f68nD.dafcW34d!')
 # auth('18521506014', 'Abc123!@#')
 # auth('18521506014', 'Abc123!@#')
 # stocks = list(get_all_securities(['stock'], date=dt.today().strftime('%Y-%m-%d')).index)
 # stocks = list(get_all_securities(['stock'], date=dt.today().strftime('%Y-%m-%d')).index)
@@ -28,20 +29,6 @@ from apscheduler.schedulers.blocking import BlockingScheduler
 pd.set_option('display.max_columns', None) # 设置显示最大行
 pd.set_option('display.max_columns', None) # 设置显示最大行
 fre = '1d'
 fre = '1d'
 
 
-def run(seq):
-    '''阻塞线程接收行情回调'''
-    import time
-    client = xtdata.get_client()
-    while True:
-        time.sleep(3)
-        now_date = dt.now()
-        if not client.is_connected() or dt.now() > now_date.replace(hour=15, minute=0, second=0):
-            xtdata.unsubscribe_quote(seq)
-            print(f'现在时间:{dt.now()},已收盘')
-            raise Exception('行情服务连接断开')
-            break
-    return
-
 
 
 class MyXtQuantTraderCallback(XtQuantTraderCallback):
 class MyXtQuantTraderCallback(XtQuantTraderCallback):
     def on_disconnected(self):
     def on_disconnected(self):
@@ -113,32 +100,65 @@ def err_call_back(err):
     traceback.print_exc()
     traceback.print_exc()
 
 
 
 
-def hlfx(data):
-    stock_list = list(data.keys())
-    print(f'def-->hlfx, MyPid is {os.getpid()}, 本次我需要计算{len(stock_list)},now is {dt.now()}')
+def run(seq):
+    mor = datetime.datetime.strptime(
+        str(dt.now().date()) + '11:30', '%Y-%m-%d%H:%M')
+    afternoon = datetime.datetime.strptime(
+        str(dt.now().date()) + '15:00', '%Y-%m-%d%H:%M')
+    mor_1 = datetime.datetime.strptime(
+        str(dt.now().date()) + '11:10', '%Y-%m-%d%H:%M')
+    """阻塞线程接收行情回调"""
+    import time
+    client = xtdata.get_client()
+    while True:
+        now_date = dt.now()
+        if not client.is_connected():
+            xtdata.unsubscribe_quote(seq)
+            raise Exception('行情服务连接断开')
+        # if mor < dt.now() < mor_1:
+        #     xtdata.unsubscribe_quote(seq)
+        #     print(f'现在时间:{dt.now()},已休市')
+        #     sys.exit()
+        #     break
+        #     return 0
+        elif dt.now() > afternoon:
+            xtdata.unsubscribe_quote(seq)
+            print(f'现在时间:{dt.now()},已收盘')
+            sys.exit()
+            break
+
+    return
+
+
+def hlfx(stock_list, data):
+    # stock_list = list(data.keys())
+    # print(f'def-->hlfx, MyPid is {os.getpid()}, 本次我需要计算{len(stock_list)},now is {dt.now()}')
 
 
     # 获得hlfx_pool池子
     # 获得hlfx_pool池子
-    engine_hlfx_pool = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/hlfx_pool?charset=utf8')
+    engine_hlfx_pool = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/hlfx_pool?charset=utf8',
+                                     pool_size=100, pool_recycle=3600, max_overflow=50, pool_timeout=60)
     results = []
     results = []
-    results.extend(pd.read_sql_query(
-        'select value from `%s`' % fre, engine_hlfx_pool).iloc[-1, 0].split(","))
-    print(f'本次hlfx_pool有{len(results)}个个股')
+    results.extend(pd.read_sql_query(text(
+        'select value from `%s` order by `index` desc limit 10' % fre), engine_hlfx_pool.connect()).iloc[0, 0].split(","))
+    # print(f'本次hlfx_pool有{len(results)}个个股')
 
 
-    engine_stock = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/qmt_stocks_tech?charset=utf8')
+    engine_stock = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/qmt_stocks_tech?charset=utf8',
+                                 pool_size=100, pool_recycle=3600, max_overflow=50, pool_timeout=60)
 
 
     for qmt_stock in stock_list:
     for qmt_stock in stock_list:
         # 读取qmt_stocks_whole表-前复权-信息
         # 读取qmt_stocks_whole表-前复权-信息
         try:
         try:
-            df_day = pd.read_sql_query(
-                'select time, open_front, close_front, high_front, low_front, volume_front, amount_front, dif, dea, macd,HL from `%s_%s`'
-                % (qmt_stock, fre), engine_stock)
+            df_day = pd.read_sql_query(text(
+                'select time, open_front, close_front, high_front, low_front, volume_front, amount_front, '
+                'dif, dea, macd, HL from `%s_%s`' % (qmt_stock, fre)), engine_stock.connect())
             df_day.columns = ['time', 'open', 'close', 'high', 'low', 'volume', 'amount', 'dif', 'dea', 'macd', 'HL']
             df_day.columns = ['time', 'open', 'close', 'high', 'low', 'volume', 'amount', 'dif', 'dea', 'macd', 'HL']
         except BaseException as e:
         except BaseException as e:
-            print(qmt_stock, '未能读取!', e)
+            print(qmt_stock, '未能读取!')
             pass
             pass
         else:
         else:
             # 获得最新价格信息
             # 获得最新价格信息
             get_price = data[qmt_stock]
             get_price = data[qmt_stock]
+            # print(get_price)
             # 调整time时间格式
             # 调整time时间格式
             get_price['time'] = dt.fromtimestamp(get_price['time'] / 1000.0)
             get_price['time'] = dt.fromtimestamp(get_price['time'] / 1000.0)
             # print('成功判定', get_price['time'])
             # print('成功判定', get_price['time'])
@@ -161,99 +181,102 @@ def hlfx(data):
 
 
             # 包含
             # 包含
             else:
             else:
-                # 左高,下降
-                if df_day.iloc[-2, 3] > df_day.iloc[-1, 3]:
-                    df_day.iloc[-1, 3] = min(df_day.iloc[-1, 3], get_price['high'])
-                    df_day.iloc[-1, 4] = min(df_day.iloc[-1, 4], get_price['low'])
-                # 右高,上升
-                else:
-                    df_day.iloc[-1, 3] = max(df_day.iloc[-1, 3], get_price['high'])
-                    df_day.iloc[-1, 4] = max(df_day.iloc[-1, 4], get_price['low'])
+                if len(df_day) > 2:
+                    # 左高,下降
+                    if df_day.iloc[-2, 3] > df_day.iloc[-1, 3]:
+                        df_day.iloc[-1, 3] = min(df_day.iloc[-1, 3], get_price['high'])
+                        df_day.iloc[-1, 4] = min(df_day.iloc[-1, 4], get_price['low'])
+                    # 右高,上升
+                    else:
+                        df_day.iloc[-1, 3] = max(df_day.iloc[-1, 3], get_price['high'])
+                        df_day.iloc[-1, 4] = max(df_day.iloc[-1, 4], get_price['low'])
                 # print('包含', df_day)
                 # print('包含', df_day)
 
 
             # 数合并完成,确认df_day
             # 数合并完成,确认df_day
             # print(df_day)
             # print(df_day)
 
 
             # 寻找顶底分型
             # 寻找顶底分型
-            x = len(df_day.index)-1
-            m = x - 1
-            # 底
-            if ((df_day.loc[x, 'high'] > df_day.loc[x - 1, 'high']) and (
-                    df_day.loc[x - 2, 'high'] > df_day.loc[x - 1, 'high'])):
-                df_day.loc[x, 'HL'] = 'L*'
-                # 判断底的性质
-                while m:
-                    if df_day.loc[m, 'HL'] in ['H', 'HH', 'H*']:
-                        if (x - m) > 3:
-                            # 成笔——>L
-                            df_day.loc[x, 'HL'] = 'L'
-
-                    elif df_day.loc[m, 'HL'] == 'L':
-                        if df_day.loc[m - 1, 'low'] > df_day.loc[x - 1, 'low']:
-                            # pool_list.append(qmt_stock)
-
-                            # 获得MACD,判断MACD判断背驰
-                            x_macd_dif, x_macd_dea, x_macd_macd = df_day.loc[x, 'dif'], df_day.loc[x, 'dea'], \
-                            df_day.loc[x, 'macd']
-                            m_macd_dif, m_macd_dea, m_macd_macd = df_day.loc[m, 'dif'], df_day.loc[m, 'dea'], \
-                            df_day.loc[m, 'macd']
-
-                            # 背驰底->LL
-                            if m_macd_dif < x_macd_dif:
-                                df_day.loc[x, 'HL'] = 'LL'
-                                # 产生信号,进入hlfx_pool
-                                results.append(qmt_stock)
-                            # 前一个为底更高,且中间不存在更低的底
-                            else:
+            if len(df_day) > 2:
+                x = len(df_day.index)-1
+                m = x - 1
+                # 底
+                if ((df_day.loc[x, 'high'] > df_day.loc[x - 1, 'high']) and (
+                        df_day.loc[x - 2, 'high'] > df_day.loc[x - 1, 'high'])):
+                    df_day.loc[x, 'HL'] = 'L*'
+                    # 判断底的性质
+                    while m:
+                        if df_day.loc[m, 'HL'] in ['H', 'HH', 'H*']:
+                            if (x - m) > 3:
+                                # 成笔——>L
                                 df_day.loc[x, 'HL'] = 'L'
                                 df_day.loc[x, 'HL'] = 'L'
-                                # 产生信号,进入hlfx_pool
-                                results.append(qmt_stock)
-                            break
-                        break
-                    m = m - 1
-                    if m == 0:
-                        df_day.loc[x, 'HL'] = 'L'
-
-            # 顶
-
-            elif (df_day.loc[x, 'high'] < df_day.loc[x - 1, 'high']) and (
-                    df_day.loc[x - 2, 'high'] < df_day.loc[x - 1, 'high']) and (qmt_stock in results):
-                df_day.loc[x, 'HL'] = 'H*'
-                while m:
-                    if df_day.loc[m, 'HL'] in ['L', 'LL', 'L*']:
-                        if x - m > 3:
-                            # 成笔->H
-                            df_day.loc[x, 'HL'] = 'H'
-                            # 产生卖出信号,进入hlfx_pool
-                            results.remove(qmt_stock)
-                            break
+                                break
 
 
-                    elif (df_day.loc[m, 'HL'] == 'H'):
-                        if df_day.loc[x - 1, 'high'] > df_day.loc[m - 1, 'high']:
-                            # 获得MACD,判断MACD判断背驰
-                            x_macd_dif, x_macd_dea, x_macd_macd = df_day.loc[x, 'dif'], df_day.loc[x, 'dea'], \
+                        elif df_day.loc[m, 'HL'] in ['L', 'LL', 'L*']:
+                            if df_day.loc[m - 1, 'low'] > df_day.loc[x - 1, 'low']:
+                                # pool_list.append(qmt_stock)
+
+                                # 获得MACD,判断MACD判断背驰
+                                x_macd_dif, x_macd_dea, x_macd_macd = df_day.loc[x, 'dif'], df_day.loc[x, 'dea'], \
                                 df_day.loc[x, 'macd']
                                 df_day.loc[x, 'macd']
-                            m_macd_dif, m_macd_dea, m_macd_macd = df_day.loc[m, 'dif'], df_day.loc[m, 'dea'], \
+                                m_macd_dif, m_macd_dea, m_macd_macd = df_day.loc[m, 'dif'], df_day.loc[m, 'dea'], \
                                 df_day.loc[m, 'macd']
                                 df_day.loc[m, 'macd']
 
 
-                            # MACD顶背驰
-                            if x_macd_dif < m_macd_dif:
-                                df_day.loc[x, 'HL'] = 'HH'
-                                # 产生卖出信号,进入hlfx_pool
-                                results.remove(qmt_stock)
+                                # 背驰底->LL
+                                if m_macd_dif < x_macd_dif:
+                                    df_day.loc[x, 'HL'] = 'LL'
+                                    # 产生信号,进入hlfx_pool
+                                    results.append(qmt_stock)
+                                    break
+                                # 前一个为底更高,且中间不存在更低的底
+                                else:
+                                    df_day.loc[x, 'HL'] = 'L'
+                                    # 产生信号,进入hlfx_pool
+                            break
+                        m = m - 1
+                        if m == 0:
+                            df_day.loc[x, 'HL'] = 'L'
+                            results.append(qmt_stock)
+
+                # 顶
 
 
-                            # 前一个为顶,且中间存在不包含 or 更高的顶
-                            else:
+                elif (df_day.loc[x, 'high'] < df_day.loc[x - 1, 'high']) and (
+                        df_day.loc[x - 2, 'high'] < df_day.loc[x - 1, 'high']) and (qmt_stock in results):
+                    df_day.loc[x, 'HL'] = 'H*'
+                    while m:
+                        if df_day.loc[m, 'HL'] in ['L', 'LL', 'L*']:
+                            if x - m > 3:
+                                # 成笔->H
                                 df_day.loc[x, 'HL'] = 'H'
                                 df_day.loc[x, 'HL'] = 'H'
                                 # 产生卖出信号,进入hlfx_pool
                                 # 产生卖出信号,进入hlfx_pool
                                 results.remove(qmt_stock)
                                 results.remove(qmt_stock)
-
+                                break
+
+                        elif df_day.loc[m, 'HL'] in ['H','HH', 'H*']:
+                            if df_day.loc[x - 1, 'high'] > df_day.loc[m - 1, 'high']:
+                                # 获得MACD,判断MACD判断背驰
+                                x_macd_dif, x_macd_dea, x_macd_macd = df_day.loc[x, 'dif'], df_day.loc[x, 'dea'], \
+                                    df_day.loc[x, 'macd']
+                                m_macd_dif, m_macd_dea, m_macd_macd = df_day.loc[m, 'dif'], df_day.loc[m, 'dea'], \
+                                    df_day.loc[m, 'macd']
+
+                                # MACD顶背驰
+                                if x_macd_dif < m_macd_dif:
+                                    df_day.loc[x, 'HL'] = 'HH'
+                                    # 产生卖出信号,进入hlfx_pool
+                                    results.remove(qmt_stock)
+                                    break
+
+                                # 前一个为顶,且中间存在不包含 or 更高的顶
+                                else:
+                                    df_day.loc[x, 'HL'] = 'H'
+                                    # 产生卖出信号,进入hlfx_pool
+                                    results.remove(qmt_stock)
                             break
                             break
-                        break
-                    m = m - 1
-                    if m == 0:
-                        df_day.loc[x, 'HL'] = 'H'
-    engine_stock.dispose()
+                        m = m - 1
+                        if m == 0:
+                            df_day.loc[x, 'HL'] = 'H'
+                            results.remove(qmt_stock)
+
 
 
     db_pool = pymysql.connect(host='localhost',
     db_pool = pymysql.connect(host='localhost',
                               user='root',
                               user='root',
@@ -261,44 +284,59 @@ def hlfx(data):
                               password='r6kEwqWU9!v3',
                               password='r6kEwqWU9!v3',
                               database='hlfx_pool')
                               database='hlfx_pool')
     cursor_pool = db_pool.cursor()
     cursor_pool = db_pool.cursor()
-    # print(set(results))
+
     results_list = ','.join(set(results))
     results_list = ','.join(set(results))
     sql = "INSERT INTO %s (date,value) VALUES('%s','%s')" % (fre, dt.now().strftime('%Y-%m-%d %H:%M:%S'), results_list)
     sql = "INSERT INTO %s (date,value) VALUES('%s','%s')" % (fre, dt.now().strftime('%Y-%m-%d %H:%M:%S'), results_list)
     cursor_pool.execute(sql)
     cursor_pool.execute(sql)
     db_pool.commit()
     db_pool.commit()
-    print(f'{dt.now()}写入新的results{len(results_list)}个,hlfx_pool更新')
+    print(f'{dt.now()} 新的results有{len(set(results))}, \n {set(results)}')
+    engine_stock.dispose()
     engine_hlfx_pool.dispose()
     engine_hlfx_pool.dispose()
 
 
 
 
+def prepare(data):
+    stock_list = list(data.keys())
+    if len(data.keys()) >= 12:
+        cpu_count = 12
+    else:
+        cpu_count = len(data.keys())
+    step = math.ceil(len(stock_list) / cpu_count)
 
 
-def bridge(list):
-    print(f'MyPid is {os.getpid()}, now is {dt.now()},我需要负责{len(list)}个个股数据')
-    seq = xtdata.subscribe_whole_quote(list, callback=hlfx)
-    run(seq)
+    to_hlfx_list = []
+    for i in range(0, len(stock_list), step):
+        to_hlfx_list.append([x for x in stock_list[i:i + step]])
+
+    pool = mp.Pool(processes=cpu_count, maxtasksperchild=12)
+    for m in range(len(to_hlfx_list)):
+        pool.apply_async(func=hlfx,
+                         args=(to_hlfx_list[m], data), error_callback=err_call_back)
+    pool.close()
+    pool.join()
 
 
 
 
-def prepare():
+def bridge():
+    print(f'bridge is {os.getpid()}, now is {dt.now()},开盘了')
     stocks = xtdata.get_stock_list_in_sector('沪深A股')
     stocks = xtdata.get_stock_list_in_sector('沪深A股')
+    seq = xtdata.subscribe_whole_quote(stocks, callback=prepare)
+    run(seq)
 
 
-    cpu_count = 4
-    pool = mp.Pool(processes=cpu_count, maxtasksperchild=8)
-    step = math.ceil(len(stocks) / cpu_count)
-    to_hlfx_list = []
 
 
-    for i in range(0, len(stocks), step):
-        to_hlfx_list.append([x for x in stocks[i:i + step]])
-
-    for m in range(cpu_count):
-        pool.apply_async(func=bridge,
-                         args=(to_hlfx_list[m],), error_callback=err_call_back)
-    pool.close()
-    pool.join()
+def job_func():
+    print(f"Job started at {dt.now()}")
+    # 创建子进程
+    p = mp.Process(target=bridge)
+    # 启动子进程
+    p.start()
+    # 等待子进程结束
+    p.join()
+    print(f"Job finished at {dt.now()}")
 
 
 
 
 if __name__ == '__main__':
 if __name__ == '__main__':
+    print(f'总进程pid:{os.getpid()}')
     mp.freeze_support()
     mp.freeze_support()
     pus = psutil.Process()
     pus = psutil.Process()
-    pus.cpu_affinity([0, 1, 2, 3])
+    pus.cpu_affinity([0, 1, 2, 3, 4, 5, 6, 7])
 
 
     path = r'c:\\qmt\\userdata_mini'
     path = r'c:\\qmt\\userdata_mini'
     # 生成session id 整数类型 同时运行的策略不能重复
     # 生成session id 整数类型 同时运行的策略不能重复
@@ -318,9 +356,13 @@ if __name__ == '__main__':
     subscribe_result = xt_trader.subscribe(acc)
     subscribe_result = xt_trader.subscribe(acc)
     print('对交易回调进行订阅,订阅后可以收到交易主推,返回0表示订阅成功', subscribe_result)
     print('对交易回调进行订阅,订阅后可以收到交易主推,返回0表示订阅成功', subscribe_result)
 
 
+    # job_func()
+
     scheduler = BlockingScheduler()
     scheduler = BlockingScheduler()
-    scheduler.add_job(func=prepare, trigger='cron', day_of_week='0-4', hour='9', minute='25',
-                      timezone="Asia/Shanghai")
+    scheduler.add_job(func=job_func, trigger='cron', day_of_week='0-4', hour='09', minute='25',
+                      timezone="Asia/Shanghai", max_instances=5)
+    # # scheduler.add_job(func=job_func, trigger='cron', day_of_week='0-4', hour='13', minute='00',
+    # #                   timezone="Asia/Shanghai")
     try:
     try:
         scheduler.start()
         scheduler.start()
     except (KeyboardInterrupt, SystemExit):
     except (KeyboardInterrupt, SystemExit):

+ 190 - 152
QMT/real_time.py

@@ -12,31 +12,130 @@ import pymysql
 import multiprocessing as mp
 import multiprocessing as mp
 import math
 import math
 import psutil
 import psutil
+import datetime
 from apscheduler.schedulers.blocking import BlockingScheduler
 from apscheduler.schedulers.blocking import BlockingScheduler
+import sys
+import gc
 
 
-auth('18616891214', 'Ea?*7f68nD.dafcW34d!')
-db_pool = pymysql.connect(host='localhost',
-                          user='root',
-                          port=3307,
-                          password='r6kEwqWU9!v3',
-                          database='hlfx_pool')
-cursor_pool = db_pool.cursor()
+# auth('18616891214', 'Ea?*7f68nD.dafcW34d!')
 engine_stock = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/qmt_stocks_whole?charset=utf8')
 engine_stock = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/qmt_stocks_whole?charset=utf8')
+auth('18616891214', 'Ea?*7f68nD.dafcW34d!')
+
+
+class MyXtQuantTraderCallback(XtQuantTraderCallback):
+    def on_disconnected(self):
+        """
+        连接断开
+        :return:
+        """
+        print(datetime.datetime.now(), '连接断开回调')
+
+    def on_stock_order(self, order):
+        """
+        委托回报推送
+        :param order: XtOrder对象
+        :return:
+        """
+        print(datetime.datetime.now(), '委托回调', order.order_remark)
+
+    def on_stock_trade(self, trade):
+        """
+        成交变动推送
+        :param trade: XtTrade对象
+        :return:
+        """
+        print(datetime.datetime.now(), '成交回调', trade.order_remark)
+
+    def on_order_error(self, order_error):
+        """
+        委托失败推送
+        :param order_error:XtOrderError 对象
+        :return:
+        """
+        # print("on order_error callback")
+        # print(order_error.order_id, order_error.error_id, order_error.error_msg)
+        print(f"委托报错回调 {order_error.order_remark} {order_error.error_msg}")
+
+    def on_cancel_error(self, cancel_error):
+        """
+        撤单失败推送
+        :param cancel_error: XtCancelError 对象
+        :return:
+        """
+        print(datetime.datetime.now(), sys._getframe().f_code.co_name)
+
+    def on_order_stock_async_response(self, response):
+        """
+        异步下单回报推送
+        :param response: XtOrderResponse 对象
+        :return:
+        """
+        print(f"异步委托回调 {response.order_remark}")
+
+    def on_cancel_order_stock_async_response(self, response):
+        """
+        :param response: XtCancelOrderResponse 对象
+        :return:
+        """
+        print(datetime.datetime.now(), sys._getframe().f_code.co_name)
+
+    def on_account_status(self, status):
+        """
+        :param response: XtAccountStatus 对象
+        :return:
+        """
+        print(datetime.datetime.now(), sys._getframe().f_code.co_name)
 
 
 
 
-def run(seq):
-    print(seq)
-    '''阻塞线程接收行情回调'''
+# 指定客户端所在路径
+path = r'c:\\qmt\\userdata_mini'
+# 生成session id 整数类型 同时运行的策略不能重复
+session_id = int(time.time())
+xt_trader = XtQuantTrader(path, session_id)
+# 创建资金账号为 800068 的证券账号对象
+acc = StockAccount('920000207040', 'SECURITY')
+# 创建交易回调类对象,并声明接收回调
+callback = MyXtQuantTraderCallback()
+xt_trader.register_callback(callback)
+# 启动交易线程
+xt_trader.start()
+# 建立交易连接,返回0表示连接成功
+connect_result = xt_trader.connect()
+print('建立交易连接,返回0表示连接成功', connect_result)
+# 对交易回调进行订阅,订阅后可以收到交易主推,返回0表示订阅成功
+subscribe_result = xt_trader.subscribe(acc)
+print('对交易回调进行订阅,订阅后可以收到交易主推,返回0表示订阅成功', subscribe_result)
+
+
+def run(seq, pid):
+    mor = datetime.datetime.strptime(
+        str(dt.now().date()) + '11:30', '%Y-%m-%d%H:%M')
+    afternoon = datetime.datetime.strptime(
+        str(dt.now().date()) + '15:00', '%Y-%m-%d%H:%M')
+    mor_1 = datetime.datetime.strptime(
+        str(dt.now().date()) + '12:59', '%Y-%m-%d%H:%M')
+    """阻塞线程接收行情回调"""
     import time
     import time
     client = xtdata.get_client()
     client = xtdata.get_client()
     while True:
     while True:
         time.sleep(3)
         time.sleep(3)
         now_date = dt.now()
         now_date = dt.now()
-        if not client.is_connected() or dt.now() > now_date.replace(hour=13, minute=26, second=0):
+        if not client.is_connected():
             xtdata.unsubscribe_quote(seq)
             xtdata.unsubscribe_quote(seq)
             raise Exception('行情服务连接断开')
             raise Exception('行情服务连接断开')
+        # if mor < dt.now() < mor_1:
+        #     xtdata.unsubscribe_quote(seq)
+        #     print(f'现在时间:{dt.now()},已休市')
+        #     sys.exit()
+        #     break
+        #     return 0
+        elif dt.now() > afternoon:
+            xtdata.unsubscribe_quote(seq)
+            print(f'现在时间:{dt.now()},已收盘')
+            sys.exit()
             break
             break
-    return
+            # return 0
+    # return
 
 
 
 
 def real_price(datas):
 def real_price(datas):
@@ -57,13 +156,13 @@ def ma(stock, num, data):
     except:
     except:
         return 9999999
         return 9999999
     else:
     else:
-        ma_num = (sum(df['close_front'][i:]) + data[stock]['lastPrice'])/num
+        ma_num = (sum(df['close_front'][i:]) + data[stock]['lastPrice']) / num
         return ma_num
         return ma_num
 
 
 
 
 def ma_1(stock, num):
 def ma_1(stock, num):
     global engine_stock
     global engine_stock
-    i = (num) * -1
+    i = num * -1
     try:
     try:
         df = pd.read_sql_query(
         df = pd.read_sql_query(
             'select close_front from `%s_1d`' % stock, engine_stock)
             'select close_front from `%s_1d`' % stock, engine_stock)
@@ -86,53 +185,61 @@ def his_vol(stock, num):
         return df['volume_front'].iloc[num]
         return df['volume_front'].iloc[num]
 
 
 
 
-def ma_judge(data, stock_list, rate, results):
+def ma_judge(data, list_judge, rate, results):
     # print(f',收到的data数据为:{len(data.keys())},stock_pool长度为{len(stock_list)},now is {dt.now()}')
     # print(f',收到的data数据为:{len(data.keys())},stock_pool长度为{len(stock_list)},now is {dt.now()}')
-    list_judge = list(set(data.keys()) & set(stock_list))
+
     print(f'这个ma_judge的PID为:{os.getpid()},本轮计算:{len(list_judge)}个股')
     print(f'这个ma_judge的PID为:{os.getpid()},本轮计算:{len(list_judge)}个股')
     for stock in list_judge:
     for stock in list_judge:
-        i = stock.replace('XSHG', 'SH').replace('XSHE', 'SZ')
-        current_price, open_price = data[i]['lastPrice'], data[i]['open']
-        MA5, MA10, MA20, MA30, MA60, MA120 = ma(i, 5, data), ma(i, 10, data), ma(i, 20, data), ma(i, 30, data),\
-            ma(i, 60, data), ma(i, 120, data)
-        MA5_1 = ma_1(i, 5)
+        current_price, open_price = data[stock]['lastPrice'], data[stock]['open']
+        MA5, MA10, MA20, MA30, MA60, MA120 = ma(stock, 5, data), ma(stock, 10, data), ma(stock, 20, data), ma(stock, 30,
+                                                                                                              data), \
+            ma(stock, 60, data), ma(stock, 120, data)
+        MA5_1 = ma_1(stock, 5)
         # print(i, current_price, open_price, MA5, MA10, MA20, MA5_1)
         # print(i, current_price, open_price, MA5, MA10, MA20, MA5_1)
         # 入交易池标准:阳线\大于MA5\MA5向上\MA20<MA10\离120线有距离
         # 入交易池标准:阳线\大于MA5\MA5向上\MA20<MA10\离120线有距离
         if (current_price > open_price) & (current_price > MA5) & (MA5 > MA5_1) & (current_price < MA5 * 1.03) & (
         if (current_price > open_price) & (current_price > MA5) & (MA5 > MA5_1) & (current_price < MA5 * 1.03) & (
-                MA20 < MA10) & (current_price > MA120 or current_price < MA120*rate):
-            if his_vol(i, -1) > his_vol(i, -2):
-                results.append(i.replace('SH', 'XSHG').replace('SZ', 'XSHE'))
+                MA20 < MA10) & (current_price > MA120 or current_price < MA120 * rate):
+            if his_vol(stock, -1) > his_vol(stock, -2):
+                results.append(stock.replace('SH', 'XSHG').replace('SZ', 'XSHE'))
 
 
 
 
-def sell_trader(data, positions_dict):
-    # for m in data:
-    #     print(m, data[m]['lastPrice'])
+def get_fundamentals(results):
+    return results
+    pass
+
+
+def sell_trader(data):
     print('卖出函数:', dt.now())
     print('卖出函数:', dt.now())
     positions = xt_trader.query_stock_positions(acc)
     positions = xt_trader.query_stock_positions(acc)
-    print('持仓总数:', len(positions))
+    positions_dict = {positions[x].stock_code: positions[x].can_use_volume for x in range(0, len(positions))}
+    print(f'今日可卖出个股总数:{len([value for value in positions_dict.values() if value != 0])}')
+    print(
+        f'目前持仓总数为:{len([positions[x].stock_code for x in range(0, len(positions)) if positions[x].volume != 0])}')
 
 
-    for stock, volume in positions_dict.items():
-        if stock in data:
+    for stock, can_use_volume in positions_dict.items():
+        if stock in data and can_use_volume != 0:
             current_price = data[stock]['lastPrice']
             current_price = data[stock]['lastPrice']
             open_price = data[stock]['open']
             open_price = data[stock]['open']
             MA5 = ma(stock, 5, data)
             MA5 = ma(stock, 5, data)
             MA5_1 = ma_1(stock, 5)
             MA5_1 = ma_1(stock, 5)
-            print(f'{stock},持仓量为{volume}当前价:{current_price},MA5:{MA5},昨日MA5:{MA5_1},开始判断:')
-            if current_price < MA5 or MA5 < MA5_1 or current_price > MA5 * 1.07:
+            print(f'{stock},持仓量为{can_use_volume}当前价:{current_price},MA5:{MA5},昨日MA5:{MA5_1},开始判断:')
+            if current_price < MA5 or MA5 < MA5_1:
                 print('卖出信号!!!!!!', stock, current_price)
                 print('卖出信号!!!!!!', stock, current_price)
-                order_id = xt_trader.order_stock(acc, stock, xtconstant.STOCK_SELL, volume,
-                                                 xtconstant.LATEST_PRICE, 0, 'strategy1', 'order_test')
+                order_id = xt_trader.order_stock(acc, stock, xtconstant.STOCK_SELL, can_use_volume,
+                                                 xtconstant.LATEST_PRICE, 0, 'MA5策略', '低于MA5趋势向下')
                 print('价格:', current_price, open_price, MA5, MA5_1)
                 print('价格:', current_price, open_price, MA5, MA5_1)
-                print(order_id, stock, volume)
+                print(order_id, stock, can_use_volume)
+            elif current_price > MA5 * 1.07:
+                print('盈利乖离率超7%!!!!!!', stock, current_price)
+                order_id = xt_trader.order_stock(acc, stock, xtconstant.STOCK_SELL, can_use_volume,
+                                                 xtconstant.LATEST_PRICE, 0, 'MA5策略', '盈利乖离率超7%')
+                print('价格:', current_price, open_price, MA5, MA5_1)
+                print(order_id, stock, can_use_volume)
         else:
         else:
             print(f'本轮没有持仓股票信息!')
             print(f'本轮没有持仓股票信息!')
 
 
 
 
-def get_fundamentals(results):
-    return results
-    pass
-
-def buy_trader(data, positions):
+def buy_trader(data):
     print('买入函数:', dt.now(), f'接受到{len(data.keys())}个个股')
     print('买入函数:', dt.now(), f'接受到{len(data.keys())}个个股')
     results = mp.Manager().list()
     results = mp.Manager().list()
     mp_list = []
     mp_list = []
@@ -140,10 +247,10 @@ def buy_trader(data, positions):
 
 
     try:
     try:
         stock_pool = pd.read_sql_query(
         stock_pool = pd.read_sql_query(
-            'select value from `%s`' % '1d', engine_hlfx_pool)
-        stock_pool = stock_pool.iloc[-1, 0].split(",")
+            'select value from `%s` order by `index` desc limit 10' % '1d', engine_hlfx_pool)
+        stock_pool = stock_pool.iloc[0, 0].split(",")
         stock_pool.sort()
         stock_pool.sort()
-        print('stock_pool',len(stock_pool))
+        print('stock_pool', len(stock_pool))
     except BaseException:
     except BaseException:
         pass
         pass
     '''
     '''
@@ -159,12 +266,13 @@ def buy_trader(data, positions):
                     results.append(stock.replace('SH', 'XSHG').replace('SZ', 'XSHE'))
                     results.append(stock.replace('SH', 'XSHG').replace('SZ', 'XSHE'))
                     print('append')
                     print('append')
     '''
     '''
-
-    step = math.ceil(len(stock_pool) / (mp.cpu_count()/2))
+    list_judge = list(set(data.keys()) & set(stock_pool))
+    print(f'本轮有{len(data.keys())}条个股信息,而list_judge有:{len(list_judge)}')
+    step = math.ceil(len(list_judge) / 2)
     print('step:', step)
     print('step:', step)
     rate = 0.8
     rate = 0.8
-    for i in range(0, len(stock_pool), step):
-        p = mp.Process(target=ma_judge, args=(data, stock_pool[i:i + step], rate, results))
+    for i in range(0, len(list_judge), step):
+        p = mp.Process(target=ma_judge, args=(data, list_judge[i:i + step], rate, results))
         mp_list.append(p)
         mp_list.append(p)
         p.start()
         p.start()
     for j in mp_list:
     for j in mp_list:
@@ -192,6 +300,12 @@ def buy_trader(data, positions):
         results_industry = ','.join(set(results_industry))
         results_industry = ','.join(set(results_industry))
         print('1d', '\n', results_industry)
         print('1d', '\n', results_industry)
 
 
+        db_pool = pymysql.connect(host='localhost',
+                                  user='root',
+                                  port=3307,
+                                  password='r6kEwqWU9!v3',
+                                  database='hlfx_pool')
+        cursor_pool = db_pool.cursor()
         sql = "INSERT INTO MA5_%s (date,value) VALUES('%s','%s')" % ('1d', dt.now().strftime('%Y-%m-%d %H:%M:%S'),
         sql = "INSERT INTO MA5_%s (date,value) VALUES('%s','%s')" % ('1d', dt.now().strftime('%Y-%m-%d %H:%M:%S'),
                                                                      results_industry)
                                                                      results_industry)
         cursor_pool.execute(sql)
         cursor_pool.execute(sql)
@@ -199,18 +313,21 @@ def buy_trader(data, positions):
 
 
         # print(len(results_industry), results_industry)
         # print(len(results_industry), results_industry)
         print(dt.now(), '数据库数据已赋值!')
         print(dt.now(), '数据库数据已赋值!')
+        cursor_pool.close()
+        db_pool.close()
 
 
         # 取值交易
         # 取值交易
-
         keep_stocks = results_industry.split(",")
         keep_stocks = results_industry.split(",")
         new_keep_stock = [stock.replace('XSHG', 'SH').replace('XSHE', 'SZ') for stock in keep_stocks]
         new_keep_stock = [stock.replace('XSHG', 'SH').replace('XSHE', 'SZ') for stock in keep_stocks]
         print(f'new_keep_stock is:{len(new_keep_stock)}')
         print(f'new_keep_stock is:{len(new_keep_stock)}')
 
 
-
-        #进入购买程序
+        # 进入购买程序
         max_pos = 7
         max_pos = 7
         for stock in new_keep_stock:
         for stock in new_keep_stock:
+            positions = xt_trader.query_stock_positions(acc)
+
             asset = xt_trader.query_stock_asset(acc)
             asset = xt_trader.query_stock_asset(acc)
+            print('bbbb', positions, asset)
             cash = asset.cash
             cash = asset.cash
             positions_dict = {positions[x].stock_code: positions[x].volume for x in range(0, len(positions)) if
             positions_dict = {positions[x].stock_code: positions[x].volume for x in range(0, len(positions)) if
                               positions[x].volume > 0}
                               positions[x].volume > 0}
@@ -218,138 +335,59 @@ def buy_trader(data, positions):
             current_price = data[stock]['lastPrice']
             current_price = data[stock]['lastPrice']
             current_high = data[stock]['high']
             current_high = data[stock]['high']
             if cash > 5000 and len(positions_dict) < max_pos and current_price > 9 \
             if cash > 5000 and len(positions_dict) < max_pos and current_price > 9 \
-                    and current_price > (current_high*0.98):
+                    and current_price > (current_high * 0.98):
                 volume = int((cash / 3 / current_price) // 100 * 100)
                 volume = int((cash / 3 / current_price) // 100 * 100)
                 print('买入信号!!!!!!', stock, volume, current_price)
                 print('买入信号!!!!!!', stock, volume, current_price)
                 order_id = xt_trader.order_stock(acc, stock, xtconstant.STOCK_BUY, volume, xtconstant.LATEST_PRICE,
                 order_id = xt_trader.order_stock(acc, stock, xtconstant.STOCK_BUY, volume, xtconstant.LATEST_PRICE,
-                                                 current_price, 'strategy1', 'order_test')
+                                                 current_price, 'MA5策略', 'MA5趋势向上')
                 print(order_id)
                 print(order_id)
             else:
             else:
-                print(f'Cash只有:{cash} 或者 现有持仓{len(positions)} 超过了{max_pos}')
+                print(f'Cash只有:{cash} 或者 现有持仓{len(positions_dict)} 超过了{max_pos}')
     engine_hlfx_pool.dispose()
     engine_hlfx_pool.dispose()
     print('一轮结束了,现在时间是:', dt.now())
     print('一轮结束了,现在时间是:', dt.now())
 
 
 
 
 def trader(data):
 def trader(data):
-    print(len(data.keys()))
-
-    # 先判断卖出条件
-    positions = xt_trader.query_stock_positions(acc)
-    print('持仓数量', len(positions))
-    if len(positions) != 0:
-        positions_dict = {positions[x].stock_code: positions[x].volume for x in range(0, len(positions))}
-        sell_trader(data, positions_dict)
-
+    sell_trader(data)
     # 买入条件
     # 买入条件
-    buy_trader(data, positions)
+    buy_trader(data)
 
 
 
 
 def bridge():
 def bridge():
-    print("start")
+    pid = os.getpid()
+    print(f'MyPid is {os.getpid()}, now is {dt.now()},开盘了')
     stocks = xtdata.get_stock_list_in_sector('沪深A股')
     stocks = xtdata.get_stock_list_in_sector('沪深A股')
     seq = xtdata.subscribe_whole_quote(stocks, callback=trader)
     seq = xtdata.subscribe_whole_quote(stocks, callback=trader)
-    run(seq)
-
-
-class MyXtQuantTraderCallback(XtQuantTraderCallback):
-    def on_disconnected(self):
-        """
-        连接断开
-        :return:
-        """
-        print(datetime.datetime.now(), '连接断开回调')
-
-    def on_stock_order(self, order):
-        """
-        委托回报推送
-        :param order: XtOrder对象
-        :return:
-        """
-        print(datetime.datetime.now(), '委托回调', order.order_remark)
-
-    def on_stock_trade(self, trade):
-        """
-        成交变动推送
-        :param trade: XtTrade对象
-        :return:
-        """
-        print(datetime.datetime.now(), '成交回调', trade.order_remark)
-
-    def on_order_error(self, order_error):
-        """
-        委托失败推送
-        :param order_error:XtOrderError 对象
-        :return:
-        """
-        # print("on order_error callback")
-        # print(order_error.order_id, order_error.error_id, order_error.error_msg)
-        print(f"委托报错回调 {order_error.order_remark} {order_error.error_msg}")
-
-    def on_cancel_error(self, cancel_error):
-        """
-        撤单失败推送
-        :param cancel_error: XtCancelError 对象
-        :return:
-        """
-        print(datetime.datetime.now(), sys._getframe().f_code.co_name)
-
-    def on_order_stock_async_response(self, response):
-        """
-        异步下单回报推送
-        :param response: XtOrderResponse 对象
-        :return:
-        """
-        print(f"异步委托回调 {response.order_remark}")
+    run(seq, pid)
 
 
-    def on_cancel_order_stock_async_response(self, response):
-        """
-        :param response: XtCancelOrderResponse 对象
-        :return:
-        """
-        print(datetime.datetime.now(), sys._getframe().f_code.co_name)
 
 
-    def on_account_status(self, status):
-        """
-        :param response: XtAccountStatus 对象
-        :return:
-        """
-        print(datetime.datetime.now(), sys._getframe().f_code.co_name)
+def job_func():
+    print(f"Job started at {dt.now()}")
+    # 创建子进程
+    p = mp.Process(target=bridge)
+    # 启动子进程
+    p.start()
+    # 等待子进程结束
+    p.join()
+    print(f"Job finished at {dt.now()}")
 
 
 
 
 if __name__ == '__main__':
 if __name__ == '__main__':
-    auth('18616891214', 'Ea?*7f68nD.dafcW34d!')
-
     mp.freeze_support()
     mp.freeze_support()
     print('cpu_count =', mp.cpu_count())
     print('cpu_count =', mp.cpu_count())
     pus = psutil.Process()
     pus = psutil.Process()
-    pus.cpu_affinity([4, 5, 6, 7])
-
-    # 指定客户端所在路径
-    path = r'c:\\qmt\\userdata_mini'
-    # 生成session id 整数类型 同时运行的策略不能重复
-    session_id = int(time.time())
-    xt_trader = XtQuantTrader(path, session_id)
-    # 创建资金账号为 800068 的证券账号对象
-    acc = StockAccount('920000207040', 'SECURITY')
-    # 创建交易回调类对象,并声明接收回调
-    callback = MyXtQuantTraderCallback()
-    xt_trader.register_callback(callback)
-    # 启动交易线程
-    xt_trader.start()
-    # 建立交易连接,返回0表示连接成功
-    connect_result = xt_trader.connect()
-    print('建立交易连接,返回0表示连接成功', connect_result)
-    # 对交易回调进行订阅,订阅后可以收到交易主推,返回0表示订阅成功
-    subscribe_result = xt_trader.subscribe(acc)
-    print('对交易回调进行订阅,订阅后可以收到交易主推,返回0表示订阅成功', subscribe_result)
+    pus.cpu_affinity([12, 13, 14, 15, 16, 17])
+
+    # job_func()
 
 
     scheduler = BlockingScheduler()
     scheduler = BlockingScheduler()
-    scheduler.add_job(func=bridge, trigger='cron', day_of_week='0-4', hour='9', minute='40',
+    scheduler.add_job(func=job_func, trigger='cron', day_of_week='0-4', hour='09', minute='40',
                       timezone="Asia/Shanghai")
                       timezone="Asia/Shanghai")
+    # scheduler.add_job(func=job_func, trigger='cron', day_of_week='0-4', hour='13', minute='05',
+    #                   timezone="Asia/Shanghai")
     try:
     try:
         scheduler.start()
         scheduler.start()
     except (KeyboardInterrupt, SystemExit):
     except (KeyboardInterrupt, SystemExit):
         pass
         pass
 
 
-
     # xtdata.subscribe_quote('000001.SZ', '1d', '', '', count=1, callback=MA)
     # xtdata.subscribe_quote('000001.SZ', '1d', '', '', count=1, callback=MA)

+ 81 - 0
QMT/test_kzz.py

@@ -0,0 +1,81 @@
+# coding:utf-8
+import pandas as pd
+import numpy as np
+from sklearn.preprocessing import MinMaxScaler
+from keras.models import Sequential
+from keras.layers import Dense, LSTM
+from keras.callbacks import EarlyStopping
+import matplotlib.pyplot as plt
+from sqlalchemy import create_engine
+
+# 加载数据
+engine_tech = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/qmt_stocks_tech?charset=utf8')
+
+
+df = pd.read_sql_table('600000.SH_1d', con=engine_tech)
+print(df)
+
+# 计算MACD指标
+ema12 = df['close_back'].ewm(span=12, adjust=False).mean()
+ema26 = df['close_back'].ewm(span=26, adjust=False).mean()
+macd = ema12 - ema26
+signal = macd.ewm(span=9, adjust=False).mean()
+df['macd'] = macd
+df['signal'] = signal
+
+# 准备数据
+data = df[['close_back', 'macd', 'signal', 'willr', 'volume_back', 'dif', 'dea', 'rsi_6', 'rsi_12', 'rsi_24']].values
+print(data)
+data = data[~np.isnan(data).any(axis=1), :]
+print('处理后', data)
+
+
+scaler = MinMaxScaler(feature_range=(0, 1))
+data = scaler.fit_transform(data)
+train_size = int(len(data) * 0.7)
+train_data = data[:train_size, :]
+test_data = data[train_size:, :]
+
+def create_dataset(dataset, look_back):
+    X, Y = [], []
+    for i in range(len(dataset) - look_back - 1):
+        X.append(dataset[i:(i + look_back), :])
+        Y.append(dataset[i + look_back, 0])
+    return np.array(X), np.array(Y)
+
+look_back = 90
+train_X, train_Y = create_dataset(train_data, look_back)
+test_X, test_Y = create_dataset(test_data, look_back)
+
+# LSTM模型
+model = Sequential()
+model.add(LSTM(units=50, input_shape=(train_X.shape[1], train_X.shape[2])))
+model.add(Dense(units=1))
+model.compile(optimizer='adam', loss='mean_squared_error')
+
+# 训练模型
+early_stop = EarlyStopping(monitor='val_loss', patience=10)
+history = model.fit(train_X, train_Y, epochs=100, batch_size=1, validation_data=(test_X, test_Y), callbacks=[early_stop], verbose=2)
+
+# 绘制损失函数
+plt.plot(history.history['loss'], label='train')
+plt.plot(history.history['val_loss'], label='test')
+plt.legend()
+plt.show()
+
+# 预测未来30天的涨跌
+last_data = data[-look_back:, :]
+last_data = np.expand_dims(last_data, axis=0)
+predictions = []
+for i in range(30):
+    prediction = model.predict(last_data)
+    predictions.append(prediction)
+    last_data = np.concatenate([last_data[:, 1:, :], prediction.reshape(1, 1, 3)], axis=1)
+predictions = scaler.inverse_transform(np.array(predictions).reshape(-1, 1))
+
+# 绘制预测结果
+plt.plot(predictions, label='predicted')
+plt.plot(df['back_close'].tail(30).reset_index(drop=True), label='actual')
+plt.legend()
+plt.show()
+

+ 17 - 11
backtrader/230202_backtrader.py

@@ -12,6 +12,8 @@ import math
 from datetime import datetime as dt
 from datetime import datetime as dt
 import multiprocessing as mp
 import multiprocessing as mp
 from backtrader.feeds import PandasData
 from backtrader.feeds import PandasData
+import platform
+import psutil
 
 
 
 
 # import multiprocessing
 # import multiprocessing
@@ -151,18 +153,22 @@ def err_call_back(err):
 
 
 
 
 def to_df(lt):
 def to_df(lt):
-    df = pd.DataFrame(list(lt), columns=['周期', '波动率', '乖离率', '盈利个数', '盈利比例', '总盈利', '平均盈利', '最大盈利',
+    print('开始存数据')
+    df = pd.DataFrame(list(lt), columns=['周期', '波动率', 'MA5斜率', '盈利个数', '盈利比例', '总盈利', '平均盈利', '最大盈利',
                                '最小盈利', '总亏损', '平均亏损', '最大亏损', '最小亏损'])
                                '最小盈利', '总亏损', '平均亏损', '最大亏损', '最小亏损'])
-    df.sort_values(by=['周期', '波动率', '乖离率'], ascending=True, inplace=True)
+    df.sort_values(by=['周期', '波动率', 'MA5斜率'], ascending=True, inplace=True)
     df = df.reset_index(drop=True)
     df = df.reset_index(drop=True)
-    df.to_csv(f"D:\Daniel\策略\策略穷举{dt.now().strftime('%Y%m%d')}.csv", index=True, encoding='utf-8', mode='w')
-    print(df)
+    if platform.node() == 'DanieldeMBP.lan':
+        df.to_csv(f"/Users/daniel/Documents/策略/策略穷举{dt.now().strftime('%Y%m%d%H%m%S')}.csv", index=True, encoding='utf_8_sig', mode='w')
+    else:
+        df.to_csv(f"C:\Daniel\策略\策略穷举{dt.now().strftime('%Y%m%d%H%m%S' )}.csv", index=True, encoding='utf_8_sig', mode='w')
+    print(f'结果:{df}')
 
 
 
 
 def backtrader(list_date, table_list, result, result_change, result_change_fall, num, Volatility, rate, err_list):
 def backtrader(list_date, table_list, result, result_change, result_change_fall, num, Volatility, rate, err_list):
     print(f'{num}天波动率为{Volatility}%乖离率为{rate}', 'myPID is ', os.getpid())
     print(f'{num}天波动率为{Volatility}%乖离率为{rate}', 'myPID is ', os.getpid())
     sttime = dt.now()
     sttime = dt.now()
-    engine = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/qmt_stocks_tech?charset=utf8')
+    engine = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/qmt_stocks_whole?charset=utf8')
     for stock in table_list:
     for stock in table_list:
         # print(stock)
         # print(stock)
         stk_df = pd.read_sql_table(stock, engine)
         stk_df = pd.read_sql_table(stock, engine)
@@ -207,12 +213,12 @@ def backtrader(list_date, table_list, result, result_change, result_change_fall,
                 err_list.append(stock)
                 err_list.append(stock)
             else:
             else:
                 if cerebro.broker.getvalue() > 100000.0:
                 if cerebro.broker.getvalue() > 100000.0:
-                    result_change.append((cerebro.broker.getvalue() / 10000 - 1))
+                    result_change.append((cerebro.broker.getvalue() / 100000 - 1))
                     result.append(stock)
                     result.append(stock)
                     # print('recode!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
                     # print('recode!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
                     # print(result)
                     # print(result)
                 else:
                 else:
-                    result_change_fall.append((1 - cerebro.broker.getvalue() / 10000))
+                    result_change_fall.append((1 - cerebro.broker.getvalue() / 100000))
                     # print('aaaaaaaaaaa')
                     # print('aaaaaaaaaaa')
                     # print(result_change_fall)
                     # print(result_change_fall)
 
 
@@ -252,18 +258,18 @@ if __name__ == '__main__':
                          user='root',
                          user='root',
                          port=3307,
                          port=3307,
                          password='r6kEwqWU9!v3',
                          password='r6kEwqWU9!v3',
-                         database='qmt_stocks')
+                         database='qmt_stocks_whole')
     cursor = db.cursor()
     cursor = db.cursor()
     cursor.execute("show tables like '%%%s%%' " % fre)
     cursor.execute("show tables like '%%%s%%' " % fre)
     table_list = [tuple[0] for tuple in cursor.fetchall()]
     table_list = [tuple[0] for tuple in cursor.fetchall()]
     # print(table_list)
     # print(table_list)
-    # table_list = table_list[0:100]
+    table_list = table_list[0:500]
 
 
     list_date = mp.Manager().list()
     list_date = mp.Manager().list()
     thread_list = []
     thread_list = []
     pool = mp.Pool(processes=mp.cpu_count())
     pool = mp.Pool(processes=mp.cpu_count())
-    for num in range(60, 100, 20):
-        for Volatility in range(5, 7, 1):
+    for num in range(60, 80, 20):
+        for Volatility in range(5, 8, 1):
             for rate in range(7, 9, 1):
             for rate in range(7, 9, 1):
                 step = math.ceil(len(table_list) / mp.cpu_count())
                 step = math.ceil(len(table_list) / mp.cpu_count())
                 result = []
                 result = []

+ 3 - 3
backtrader/230215_backtrader.py

@@ -128,7 +128,7 @@ class TestStrategy(bt.Strategy):
                     and (((lowest * (1 - vola)) < self.low[-2] < (lowest * (1 + vola))) or (
                     and (((lowest * (1 - vola)) < self.low[-2] < (lowest * (1 + vola))) or (
                     (lowest * (1 - vola)) < self.low[-1] < (lowest * (1 + vola)))):
                     (lowest * (1 - vola)) < self.low[-1] < (lowest * (1 + vola)))):
                 self.order = self.buy()
                 self.order = self.buy()
-            elif self.hl[0] == 5 and ((highest * (1 - vola)) < self.high[-2] < (highest * (1 + vola))):
+            elif self.hl[0] == 5 or ((highest * (1 - vola)) < self.high[-2] < (highest * (1 + vola))):
                 self.order = self.close()
                 self.order = self.close()
         '''
         '''
                 if len(self) > self.params.num:
                 if len(self) > self.params.num:
@@ -279,11 +279,11 @@ if __name__ == '__main__':
     cursor.execute("show tables like '%%%s%%' " % fre)
     cursor.execute("show tables like '%%%s%%' " % fre)
     table_list = [tuple[0] for tuple in cursor.fetchall()]
     table_list = [tuple[0] for tuple in cursor.fetchall()]
     # print(table_list)
     # print(table_list)
-    # table_list = table_list[0:100]
+    table_list = table_list[0:100]
 
 
     list_date = mp.Manager().list()
     list_date = mp.Manager().list()
     thread_list = []
     thread_list = []
-    pool = mp.Pool(processes=mp.cpu_count())
+    pool = mp.Pool(processes=int(mp.cpu_count()/2))
     for num in range(60, 180, 20):
     for num in range(60, 180, 20):
         for Volatility in range(5, 8, 1):
         for Volatility in range(5, 8, 1):
             for rate in range(7, 8, 1):
             for rate in range(7, 8, 1):

+ 2 - 2
backtrader/230219_backtrader.py

@@ -187,8 +187,8 @@ def to_df(lt):
                                '最小盈利', '总亏损', '平均亏损', '最大亏损', '最小亏损'])
                                '最小盈利', '总亏损', '平均亏损', '最大亏损', '最小亏损'])
     df.sort_values(by=['周期', '波动率', '量能增长率'], ascending=True, inplace=True)
     df.sort_values(by=['周期', '波动率', '量能增长率'], ascending=True, inplace=True)
     df = df.reset_index(drop=True)
     df = df.reset_index(drop=True)
-    # df.to_csv(f"D:\Daniel\策略\策略穷举{dt.now().strftime('%Y%m%d')}.csv", index=True, encoding='utf-8', mode='w')
-    df.to_csv(f"/Users/daniel/Documents/策略/策略穷举{dt.now().strftime('%Y%m%d')}.csv", index=True, encoding='utf-8', mode='w')
+    df.to_csv(f"C:\Daniel\策略\策略穷举{dt.now().strftime('%Y%m%d')}.csv", index=True, encoding='utf-8', mode='w')
+    # df.to_csv(f"/Users/daniel/Documents/策略/策略穷举{dt.now().strftime('%Y%m%d')}.csv", index=True, encoding='utf-8', mode='w')
     print(df)
     print(df)
 
 
 
 

+ 336 - 0
backtrader/230224_backtrader.py

@@ -0,0 +1,336 @@
+import os
+import traceback
+
+import numpy as np
+from sqlalchemy import create_engine
+import pandas as pd
+import pymysql
+import backtrader as bt
+import backtrader.indicators as btind
+import datetime
+import math
+from datetime import datetime as dt
+import multiprocessing as mp
+from backtrader.feeds import PandasData
+import platform
+
+
+# import multiprocessing
+# import matplotlib
+
+class MyPandasData(PandasData):
+    lines = ('hl', 'dif', 'dea', 'macd', 'rsi_6', 'rsi_12', 'rsi_24',)
+    params = (('hl', 7),
+              ('dif', 8),
+              ('dea', 9),
+              ('macd', 10),
+              ('rsi_6', 11),
+              ('rsi_12', 12),
+              ('rsi_24', 13),
+              )
+    '''
+    lines = ('change_pct', 'net_amount_main', 'net_pct_main', 'net_amount_xl', 'net_pct_xl', 'net_amount_l', 'net_pct_l'
+             , 'net_amount_m', 'net_pct_m', 'net_amount_s', 'net_pct_s',)
+    params = (('change_pct', 7),
+              ('net_amount_main', 8),
+              ('net_pct_main', 9),
+              ('net_amount_xl', 10),
+              ('net_pct_xl', 11),
+              ('net_amount_l', 12),
+              ('net_pct_l', 13),
+              ('net_amount_m', 14),
+              ('net_pct_m', 15),
+              ('net_amount_s', 16),
+              ('net_pct_s', 17),
+              )
+    '''
+
+
+class TestStrategy(bt.Strategy):
+    params = (
+        ("num", 3),
+        ('Volatility', 0),
+        ('rate', 5),  # 注意要有逗号!!
+    )
+
+    def log(self, txt, dt=None):
+        ''' Logging function for this strategy'''
+        dt = dt or self.datas[0].datetime.date(0)
+        # print('%s, %s' % (dt.isoformat(), txt))
+
+    def __init__(self):
+        # self.num = num
+        # self.Volatility = Volatility/100
+        # Keep a reference to the "close" line in the data[0] dataseries
+        self.pos_price = 0
+        self.dataclose = self.datas[0].close
+        self.dataopen = self.datas[0].open
+        self.high = self.datas[0].high
+        self.low = self.datas[0].low
+        self.volume = self.datas[0].volume
+        self.hl = self.datas[0].hl
+        self.dif = self.datas[0].dif
+        self.dea = self.datas[0].dea
+        self.macd = self.datas[0].macd
+        self.rsi_6 = self.datas[0].rsi_6
+        self.rsi_12 = self.datas[0].rsi_12
+        self.rsi_24 = self.datas[0].rsi_24
+        # self.change_pct = self.datas[0].change_pct
+        # self.net_amount_main = self.datas[0].net_amount_main
+        # self.net_pct_main = self.datas[0].net_pct_main
+        # self.net_amount_xl = self.datas[0].net_amount_xl
+        # self.net_pct_xl = self.datas[0].net_pct_xl
+        # self.net_amount_l = self.datas[0].net_amount_l
+        # self.net_pct_l = self.datas[0].net_pct_l
+        self.sma5 = btind.MovingAverageSimple(self.datas[0].close, period=5)
+        self.sma10 = btind.MovingAverageSimple(self.datas[0].close, period=10)
+        self.sma20 = btind.MovingAverageSimple(self.datas[0].close, period=20)
+
+    def notify_order(self, order):
+        """
+        订单状态处理
+
+        Arguments:
+            order {object} -- 订单状态
+        """
+        if order.status in [order.Submitted, order.Accepted]:
+            # 如订单已被处理,则不用做任何事情
+            return
+
+        # 检查订单是否完成
+        if order.status in [order.Completed]:
+            if order.isbuy():
+                self.buyprice = order.executed.price
+                self.buycomm = order.executed.comm
+            self.bar_executed = len(self)
+
+        # 订单因为缺少资金之类的原因被拒绝执行
+        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
+            pass
+            # self.log('Order Canceled/Margin/Rejected')
+
+        # 订单状态处理完成,设为空
+        self.order = None
+
+    def notify_trade(self, trade):
+        """
+        交易成果
+
+        Arguments:
+            trade {object} -- 交易状态
+        """
+        if not trade.isclosed:
+            return
+
+        # 显示交易的毛利率和净利润
+        # self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' % (trade.pnl, trade.pnlcomm))
+
+    def next(self):
+        # print(self.num,self.Volatility)
+        # Simply log the closing price of the series from the reference
+        # self.sma20[-2] < self.sma20[-1] < self.sma20[0] and self.sma10[-2] < self.sma10[-1] < self.sma10[0]
+        # and (self.sma5[-1] < self.sma10[-1])
+        # and (self.net_pct_l[0] > 10) and (self.net_pct_xl[0] > 3)  \
+        # and (self.net_amount_main[-1] > 0) and (self.net_amount_main[0] > 0)
+
+
+        if len(self) > self.params.num:
+            vola = self.params.Volatility / 100
+            rate = self.params.rate / 100
+            lowest = np.min(self.low.get(size=self.params.num))
+            highest = np.max(self.high.get(size=self.params.num))
+            if (self.hl[-2] == 2 or self.hl[-2] == 1) and self.dataclose[0] > self.sma5[0] > self.sma5[-1] \
+                    and self.sma5[-3]/self.sma5[-2] > self.sma5[-2]/self.sma5[-1] > (1+rate) \
+                    and self.sma5[0] > self.sma5[-1]\
+                    and (((lowest * (1 - vola)) < self.low[-2] < (lowest * (1 + vola))) or (
+                    (lowest * (1 - vola)) < self.low[-1] < (lowest * (1 + vola)))) \
+                    and self.volume[0] >= self.volume[-1] and self.dataclose[0] > self.dataopen[0] \
+                    and self.sma5[0] < self.sma10[0] < self.sma20:
+                self.order = self.buy()
+                self.pos_price = self.low[-1]
+            elif (self.hl[0] == 5 and ((highest * (1 - vola)) < self.high[-2] < (highest * (1 + vola)))) \
+                    or self.dataclose[0] < self.pos_price:
+                self.order = self.close()
+                self.pos_price = 0
+
+
+
+    def stop(self):
+        # pass
+        self.log(u'(MA趋势交易效果) Ending Value %.2f' % (self.broker.getvalue()))
+
+
+def err_call_back(err):
+    print(f'出错啦~ error:{str(err)}')
+    traceback.format_exc(err)
+
+
+def to_df(lt):
+    print('开始存数据')
+    df = pd.DataFrame(list(lt), columns=['周期', '波动率', 'MA5斜率', '盈利个数', '盈利比例', '总盈利', '平均盈利', '最大盈利',
+                               '最小盈利', '总亏损', '平均亏损', '最大亏损', '最小亏损'])
+    df.sort_values(by=['周期', '波动率', 'MA5斜率'], ascending=True, inplace=True)
+    df = df.reset_index(drop=True)
+    if platform.node() == 'DanieldeMBP.lan':
+        df.to_csv(f"/Users/daniel/Documents/策略/策略穷举{dt.now().strftime('%Y%m%d')}.csv", index=True, encoding='utf-8', mode='w')
+    else:
+        df.to_csv(f"C:\Daniel\策略\策略穷举{dt.now().strftime('%Y%m%d')}.csv", index=True, encoding='utf-8', mode='w')
+    print(f'结果:{df}')
+
+
+def backtrader(list_date, table_list, result, result_change, result_change_fall, num, Volatility, rate, err_list):
+    print(f'{num}天波动率为{Volatility}%MA5斜率为{rate}', 'myPID is ', os.getpid())
+    sttime = dt.now()
+    engine = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/qmt_stocks_tech?charset=utf8')
+    for stock in table_list:
+        # print(stock)
+        stk_df = pd.read_sql_table(stock, engine)
+        stk_df.time = pd.to_datetime(stk_df.time)
+        try:
+            stk_df['HL'] = stk_df['HL'].map({'L': 1,
+                                             'LL': 2,
+                                             'L*': 3,
+                                             'H': 4,
+                                             'HH': 5,
+                                             'H*': 6,
+                                             '-': 7})
+        except BaseException:
+            print(f'{stock}数据不全,不做测试')
+        else:
+            if len(stk_df) > 60:
+                cerebro = bt.Cerebro()
+                cerebro.addstrategy(TestStrategy, num=num, Volatility=Volatility, rate=rate)
+                cerebro.addsizer(bt.sizers.FixedSize, stake=10000)
+                data = MyPandasData(dataname=stk_df,
+                                    fromdate=datetime.datetime(2017, 1, 1),
+                                    todate=datetime.datetime(2022, 10, 30),
+                                    datetime='time',
+                                    open='open_back',
+                                    close='close_back',
+                                    high='high_back',
+                                    low='low_back',
+                                    volume='volume_back',
+                                    hl='HL',
+                                    dif='dif',
+                                    dea='dea',
+                                    macd='macd',
+                                    rsi_6='rsi_6',
+                                    rsi_12='rsi_12',
+                                    rsi_24='rsi_24',
+                                    # change,_pct='change_pct',
+                                    # net_amount_main='net_amount_main',
+                                    # net_pct_main='net_pct_main',
+                                    # net_amount_xl='net_amount_xl',
+                                    # net_pct_xl='net_pct_xl',
+                                    # net_amount_l='net_amount_l',
+                                    # net_pct_l='net_pct_l',
+                                    # net_amount_m='net_amount_m',
+                                    # net_pct_m='net_pct_m',
+                                    # net_amount_s='net_amount_s',
+                                    # net_pct_s='net_pct_s',
+                                    )
+                # print('取值完成')
+                cerebro.adddata(data, name=stock)
+                cerebro.broker.setcash(100000.0)
+                cerebro.broker.setcommission(0.005)
+                cerebro.addanalyzer(bt.analyzers.PyFolio)
+                # 策略执行前的资金
+                # print('启动资金: %.2f' % cerebro.broker.getvalue())
+                try:
+                    # 策略执行
+                    cerebro.run()
+                except IndexError:
+                    err_list.append(stock)
+                else:
+                    if cerebro.broker.getvalue() > 100000.0:
+                        result_change.append((cerebro.broker.getvalue() / 10000 - 1))
+                        result.append(stock)
+                        # print('recode!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
+                        # print(result)
+                    else:
+                        result_change_fall.append((1 - cerebro.broker.getvalue() / 10000))
+                        # print('aaaaaaaaaaa')
+                        # print(result_change_fall)
+
+    if len(result) * len(result_change) * len(result_change_fall) != 0:
+        print(f'以{num}内最低值波动{Volatility}为支撑、MA5斜率为{rate}%,结果状态为:')
+        print('正盈利的个股为:', len(result_change), '成功率为:', len(result) / len(table_list))
+        print(
+            f'总盈利:{np.sum(result_change)} 平均盈利:{np.mean(result_change)},最大盈利:{np.max(result_change)}, 最小盈利:{np.min(result_change)}')
+        print(
+            f'总亏损:{np.sum(result_change_fall)},平均亏损:{np.mean(result_change_fall)},最大亏损:{np.min(result_change_fall)} 最小亏损:{np.max(result_change_fall)}')
+
+        list_date.append([num, Volatility, rate, len(result), len(result) / len(table_list), np.nansum(result_change),
+                          np.nanmean(result_change), np.nanmax(result_change), np.min(result_change),
+                          np.nansum(result_change_fall), np.nanmean(result_change_fall),
+                          np.nanmin(result_change_fall), np.nanmax(result_change_fall)])
+        to_df(list_date)
+        endtime = dt.now()
+        print(f'{num}天波动率为{Volatility}%MA5斜率为{rate},myPID is {os.getpid()}.本轮耗时为{endtime - sttime}')
+    else:
+        print('阿欧', len(result), len(result_change), len(result_change_fall), num, Volatility, rate, err_list)
+        list_date.append([num, Volatility, rate, 0, len(result) / len(table_list), len(result),
+                          len(result), len(result), len(result), len(result), len(result), len(result), 0])
+    to_df(list_date)
+    # cerebro.plot()
+
+
+# df = pd.DataFrame(
+#     columns=['周期', '波动率', 'MA5斜率', '盈利个数', '盈利比例', '总盈利', '平均盈利', '最大盈利', '最小盈利', '总亏损',
+#              '平均亏损', '最大亏损', '最小亏损'])
+if __name__ == '__main__':
+    starttime = dt.now()
+    print(starttime)
+    print(type(platform.node()))
+    # engine = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/hlfx?charset=utf8', poolclass=NullPool)
+
+    # stocks = pd.read_sql_query(
+    #                     'select value from MA5_1d', engine_hlfx)
+
+    fre = '1d'
+    db = pymysql.connect(host='localhost',
+                         user='root',
+                         port=3307,
+                         password='r6kEwqWU9!v3',
+                         database='qmt_stocks_tech')
+    cursor = db.cursor()
+    cursor.execute("show tables like '%%%s%%' " % fre)
+    table_list = [tuple[0] for tuple in cursor.fetchall()]
+    # print(table_list)
+    table_list = table_list[0:10]
+
+    list_date = mp.Manager().list()
+    thread_list = []
+    pool = mp.Pool(processes=mp.cpu_count())
+    for num in range(60, 180, 20):
+        for Volatility in range(5, 8, 1):
+            for rate in range(1, 3, 1):
+                step = math.ceil(len(table_list) / mp.cpu_count())
+                result = []
+                result_change = []
+                result_change_fall = []
+                err_list = []
+                print(f'{num}天波动率为{Volatility}%MA5斜率为{rate}')
+                # for i in range(0, len(table_list), step):
+                stattime = dt.now()
+                # thd = threading.local()
+                # print(i)
+                # p = mp.Process(target=backtrader, args=(df, table_list, result, result_change, result_change_fall,
+                #                                         num, Volatility, rate, err_list))
+                # thread_list.append(p)
+                pool.apply_async(func=backtrader,
+                                 args=(list_date, table_list, result, result_change, result_change_fall,
+                                       num, Volatility, rate, err_list,), error_callback=err_call_back)
+                # p.start()
+                # p.join()
+                # print(thread_list)
+    # for thread in thread_list:
+    #     thread.start()
+    # for thread in thread_list:
+    #     thread.join()
+    pool.close()
+    pool.join()
+
+    edtime = dt.now()
+    print('总耗时:', edtime - starttime)
+    # df.to_csv(r'C:\Users\Daniel\Documents\策略穷举2.csv', index=True)

+ 329 - 0
backtrader/230429_bt.py

@@ -0,0 +1,329 @@
+import os
+import traceback
+import numpy as np
+from sqlalchemy import create_engine
+import pandas as pd
+import pymysql
+import backtrader as bt
+import backtrader.indicators as btind
+import datetime
+import math
+from datetime import datetime as dt
+import multiprocessing as mp
+from backtrader.feeds import PandasData
+import platform
+# import multiprocessing
+# import matplotlib
+
+class MyPandasData(PandasData):
+    lines = ('hl', 'dif', 'dea', 'macd', 'rsi_6', 'rsi_12', 'rsi_24',)
+    params = (('hl', 7),
+              ('dif', 8),
+              ('dea', 9),
+              ('macd', 10),
+              ('rsi_6', 11),
+              ('rsi_12', 12),
+              ('rsi_24', 13),
+              )
+    '''
+    lines = ('change_pct', 'net_amount_main', 'net_pct_main', 'net_amount_xl', 'net_pct_xl', 'net_amount_l', 'net_pct_l'
+             , 'net_amount_m', 'net_pct_m', 'net_amount_s', 'net_pct_s',)
+    params = (('change_pct', 7),
+              ('net_amount_main', 8),
+              ('net_pct_main', 9),
+              ('net_amount_xl', 10),
+              ('net_pct_xl', 11),
+              ('net_amount_l', 12),
+              ('net_pct_l', 13),
+              ('net_amount_m', 14),
+              ('net_pct_m', 15),
+              ('net_amount_s', 16),
+              ('net_pct_s', 17),
+              )
+    '''
+
+
+class TestStrategy(bt.Strategy):
+    params = (
+        ("num", 3),
+        ('Volatility', 0),
+        ('rate', 5),  # 注意要有逗号!!
+    )
+
+    def log(self, txt, dt=None):
+        ''' Logging function for this strategy'''
+        dt = dt or self.datas[0].datetime.date(0)
+        # print('%s, %s' % (dt.isoformat(), txt))
+
+    def __init__(self):
+        # self.num = num
+        # self.Volatility = Volatility/100
+        # Keep a reference to the "close" line in the data[0] dataseries
+        self.pos_price = 0
+        self.dataclose = self.datas[0].close
+        self.dataopen = self.datas[0].open
+        self.high = self.datas[0].high
+        self.low = self.datas[0].low
+        self.volume = self.datas[0].volume
+        self.hl = self.datas[0].hl
+        self.dif = self.datas[0].dif
+        self.dea = self.datas[0].dea
+        self.macd = self.datas[0].macd
+        self.rsi_6 = self.datas[0].rsi_6
+        self.rsi_12 = self.datas[0].rsi_12
+        self.rsi_24 = self.datas[0].rsi_24
+        # self.change_pct = self.datas[0].change_pct
+        # self.net_amount_main = self.datas[0].net_amount_main
+        # self.net_pct_main = self.datas[0].net_pct_main
+        # self.net_amount_xl = self.datas[0].net_amount_xl
+        # self.net_pct_xl = self.datas[0].net_pct_xl
+        # self.net_amount_l = self.datas[0].net_amount_l
+        # self.net_pct_l = self.datas[0].net_pct_l
+        self.sma5 = btind.MovingAverageSimple(self.datas[0].close, period=5)
+        self.sma10 = btind.MovingAverageSimple(self.datas[0].close, period=10)
+        self.sma20 = btind.MovingAverageSimple(self.datas[0].close, period=20)
+        self.sma60 = btind.MovingAverageSimple(self.datas[0].close, period=60)
+
+    def notify_order(self, order):
+        """
+        订单状态处理
+
+        Arguments:
+            order {object} -- 订单状态
+        """
+        if order.status in [order.Submitted, order.Accepted]:
+            # 如订单已被处理,则不用做任何事情
+            return
+
+        # 检查订单是否完成
+        if order.status in [order.Completed]:
+            if order.isbuy():
+                self.buyprice = order.executed.price
+                self.buycomm = order.executed.comm
+            self.bar_executed = len(self)
+
+        # 订单因为缺少资金之类的原因被拒绝执行
+        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
+            pass
+            # self.log('Order Canceled/Margin/Rejected')
+
+        # 订单状态处理完成,设为空
+        self.order = None
+
+    def notify_trade(self, trade):
+        """
+        交易成果
+
+        Arguments:
+            trade {object} -- 交易状态
+        """
+        if not trade.isclosed:
+            return
+
+        # 显示交易的毛利率和净利润
+        # self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' % (trade.pnl, trade.pnlcomm))
+
+    def next(self):
+        # print(self.num,self.Volatility)
+        # Simply log the closing price of the series from the reference
+        # self.sma20[-2] < self.sma20[-1] < self.sma20[0] and self.sma10[-2] < self.sma10[-1] < self.sma10[0]
+        # and (self.sma5[-1] < self.sma10[-1])
+        # and (self.net_pct_l[0] > 10) and (self.net_pct_xl[0] > 3)  \
+        # and (self.net_amount_main[-1] > 0) and (self.net_amount_main[0] > 0)
+
+        if len(self) > self.params.num:
+            vola = self.params.Volatility / 100
+            rate = self.params.rate / 100
+            lowest = np.min(self.low.get(size=self.params.num))
+            highest = np.max(self.high.get(size=self.params.num))
+            if (self.hl[-2] == 2 or self.hl[-2] == 1) and self.dataclose[0] > self.sma5[0] > self.sma5[-1] \
+                    and self.sma5[-3]/self.sma5[-2] > self.sma5[-2]/self.sma5[-1] > (1+rate) \
+                    and self.sma5[0] > self.sma5[-1] > (1+rate)\
+                    and (((lowest * (1 - vola)) < self.low[-2] < (lowest * (1 + vola))) or (
+                    (lowest * (1 - vola)) < self.low[-1] < (lowest * (1 + vola)))) \
+                    and self.volume[0] >= self.volume[-1] and self.dataclose[0] > self.dataopen[0] \
+                    and self.sma5[0] < self.sma10[0] and self.sma10[0] > self.sma20[0]:
+                while True:
+                    m = -3
+                    if (self.hl[m] == 2 or self.hl[m] == 1) and self.macd[m] < self.macd[-1] and self.dataclose[m] > self.dataclose[-1]:
+                        self.order = self.buy()
+                        self.pos_price = self.low[-1]
+                        break
+                    m -= 1
+                    if m < (-len(self)):
+                        break
+            elif ((self.hl[0] == 5 or self.dataclose[0] < self.sma5[0]) and ((highest * (1 - vola)) < self.high[-2] < (highest * (1 + vola)))) \
+                    or self.dataclose[0] < self.pos_price:
+                self.order = self.close()
+                self.pos_price = 0
+
+
+
+    def stop(self):
+        # pass
+        self.log(u'(MA趋势交易效果) Ending Value %.2f' % (self.broker.getvalue()))
+
+
+def err_call_back(err):
+    print(f'出错啦~ error:{str(err)}')
+    traceback.format_exc(err)
+
+
+def to_df(lt):
+    print('开始存数据')
+    df = pd.DataFrame(list(lt), columns=['周期', '波动率', 'MA5斜率', '盈利个数', '盈利比例', '总盈利', '平均盈利', '最大盈利',
+                               '最小盈利', '总亏损', '平均亏损', '最大亏损', '最小亏损'])
+    df.sort_values(by=['周期', '波动率', 'MA5斜率'], ascending=True, inplace=True)
+    df = df.reset_index(drop=True)
+    if platform.node() == 'DanieldeMBP.lan':
+        df.to_csv(f"/Users/daniel/Documents/策略/策略穷举{dt.now().strftime('%Y%m%d')}.csv", index=True, encoding='utf-8', mode='w')
+    else:
+        df.to_csv(f"C:\Daniel\策略\策略穷举{dt.now().strftime('%Y%m%d')}.csv", index=True, encoding='utf-8', mode='w')
+    print(f'结果:{df}')
+
+
+def backtrader(list_date, table_list, result, result_change, result_change_fall, num, Volatility, rate, err_list):
+    print(f'{num}天波动率为{Volatility}%MA5斜率为{rate}', 'myPID is ', os.getpid())
+    sttime = dt.now()
+    engine = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/qmt_stocks_tech?charset=utf8')
+    for stock in table_list:
+        # print(stock)
+        stk_df = pd.read_sql_table(stock, engine)
+        stk_df.time = pd.to_datetime(stk_df.time)
+        try:
+            stk_df['HL'] = stk_df['HL'].map({'L': 1,
+                                             'LL': 2,
+                                             'L*': 3,
+                                             'H': 4,
+                                             'HH': 5,
+                                             'H*': 6,
+                                             '-': 7})
+        except BaseException:
+            print(f'{stock}数据不全,不做测试')
+        else:
+            if len(stk_df) > 60:
+                cerebro = bt.Cerebro()
+                cerebro.addstrategy(TestStrategy, num=num, Volatility=Volatility, rate=rate)
+                cerebro.addsizer(bt.sizers.FixedSize, stake=10000)
+                data = MyPandasData(dataname=stk_df,
+                                    fromdate=datetime.datetime(2017, 1, 1),
+                                    todate=datetime.datetime(2022, 10, 30),
+                                    datetime='time',
+                                    open='open_back',
+                                    close='close_back',
+                                    high='high_back',
+                                    low='low_back',
+                                    volume='volume_back',
+                                    hl='HL',
+                                    dif='dif',
+                                    dea='dea',
+                                    macd='macd',
+                                    rsi_6='rsi_6',
+                                    rsi_12='rsi_12',
+                                    rsi_24='rsi_24',
+                                    )
+                # print('取值完成')
+                cerebro.adddata(data, name=stock)
+                cerebro.broker.setcash(100000.0)
+                cerebro.broker.setcommission(0.005)
+                cerebro.addanalyzer(bt.analyzers.PyFolio)
+                # 策略执行前的资金
+                # print('启动资金: %.2f' % cerebro.broker.getvalue())
+                try:
+                    # 策略执行
+                    cerebro.run()
+                except IndexError:
+                    err_list.append(stock)
+                else:
+                    if cerebro.broker.getvalue() > 100000.0:
+                        result_change.append((cerebro.broker.getvalue() / 10000 - 1))
+                        result.append(stock)
+                        # print('recode!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
+                        # print(result)
+                    else:
+                        result_change_fall.append((1 - cerebro.broker.getvalue() / 10000))
+                        # print('aaaaaaaaaaa')
+                        # print(result_change_fall)
+
+    if len(result) * len(result_change) * len(result_change_fall) != 0:
+        print(f'以{num}内最低值波动{Volatility}为支撑、MA5斜率为{rate}%,结果状态为:')
+        print('正盈利的个股为:', len(result_change), '成功率为:', len(result) / len(table_list))
+        print(
+            f'总盈利:{np.sum(result_change)} 平均盈利:{np.mean(result_change)},最大盈利:{np.max(result_change)}, 最小盈利:{np.min(result_change)}')
+        print(
+            f'总亏损:{np.sum(result_change_fall)},平均亏损:{np.mean(result_change_fall)},最大亏损:{np.min(result_change_fall)} 最小亏损:{np.max(result_change_fall)}')
+
+        list_date.append([num, Volatility, rate, len(result), len(result) / len(table_list), np.nansum(result_change),
+                          np.nanmean(result_change), np.nanmax(result_change), np.min(result_change),
+                          np.nansum(result_change_fall), np.nanmean(result_change_fall),
+                          np.nanmin(result_change_fall), np.nanmax(result_change_fall)])
+        to_df(list_date)
+        endtime = dt.now()
+        print(f'{num}天波动率为{Volatility}%MA5斜率为{rate},myPID is {os.getpid()}.本轮耗时为{endtime - sttime}')
+    else:
+        print('阿欧', len(result), len(result_change), len(result_change_fall), num, Volatility, rate, err_list)
+        list_date.append([num, Volatility, rate, 0, len(result) / len(table_list), len(result),
+                          len(result), len(result), len(result), len(result), len(result), len(result), 0])
+    to_df(list_date)
+    # cerebro.plot()
+
+
+# df = pd.DataFrame(
+#     columns=['周期', '波动率', 'MA5斜率', '盈利个数', '盈利比例', '总盈利', '平均盈利', '最大盈利', '最小盈利', '总亏损',
+#              '平均亏损', '最大亏损', '最小亏损'])
+if __name__ == '__main__':
+    starttime = dt.now()
+    print(starttime)
+    # print(type(platform.node()))
+    # engine = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/hlfx?charset=utf8', poolclass=NullPool)
+
+    # stocks = pd.read_sql_query(
+    #                     'select value from MA5_1d', engine_hlfx)
+
+    fre = '1d'
+    db = pymysql.connect(host='localhost',
+                         user='root',
+                         port=3307,
+                         password='r6kEwqWU9!v3',
+                         database='qmt_stocks_tech')
+    cursor = db.cursor()
+    cursor.execute("show tables like '%%%s%%' " % fre)
+    table_list = [tuple[0] for tuple in cursor.fetchall()]
+    # print(table_list)
+    # table_list = table_list[0:10]
+
+    list_date = mp.Manager().list()
+    thread_list = []
+    pool = mp.Pool(processes=mp.cpu_count())
+    for num in range(60, 180, 20):
+        for Volatility in range(5, 10, 1):
+            for rate in range(1, 4, 1):
+                step = math.ceil(len(table_list) / mp.cpu_count())
+                result = []
+                result_change = []
+                result_change_fall = []
+                err_list = []
+                print(f'{num}天波动率为{Volatility}%MA5斜率为{rate}')
+                # for i in range(0, len(table_list), step):
+                stattime = dt.now()
+                # thd = threading.local()
+                # print(i)
+                # p = mp.Process(target=backtrader, args=(df, table_list, result, result_change, result_change_fall,
+                #                                         num, Volatility, rate, err_list))
+                # thread_list.append(p)
+                pool.apply_async(func=backtrader,
+                                 args=(list_date, table_list, result, result_change, result_change_fall,
+                                       num, Volatility, rate, err_list,), error_callback=err_call_back)
+                # p.start()
+                # p.join()
+                # print(thread_list)
+    # for thread in thread_list:
+    #     thread.start()
+    # for thread in thread_list:
+    #     thread.join()
+    pool.close()
+    pool.join()
+
+    edtime = dt.now()
+    print('总耗时:', edtime - starttime)
+    # df.to_csv(r'C:\Users\Daniel\Documents\策略穷举2.csv', index=True)

+ 343 - 0
backtrader/230503_bt.py

@@ -0,0 +1,343 @@
+import os
+import traceback
+import numpy as np
+from sqlalchemy import create_engine
+import pandas as pd
+import pymysql
+import backtrader as bt
+import backtrader.indicators as btind
+import datetime
+import math
+from datetime import datetime as dt
+import multiprocessing as mp
+from backtrader.feeds import PandasData
+import platform
+import psutil
+# import multiprocessing
+# import matplotlib
+
+
+class MyPandasData(PandasData):
+    lines = ('hl', 'dif', 'dea', 'macd', 'rsi_6', 'rsi_12', 'rsi_24',)
+    params = (('hl', 7),
+              ('dif', 8),
+              ('dea', 9),
+              ('macd', 10),
+              ('rsi_6', 11),
+              ('rsi_12', 12),
+              ('rsi_24', 13),
+              )
+    '''
+    lines = ('change_pct', 'net_amount_main', 'net_pct_main', 'net_amount_xl', 'net_pct_xl', 'net_amount_l', 'net_pct_l'
+             , 'net_amount_m', 'net_pct_m', 'net_amount_s', 'net_pct_s',)
+    params = (('change_pct', 7),
+              ('net_amount_main', 8),
+              ('net_pct_main', 9),
+              ('net_amount_xl', 10),
+              ('net_pct_xl', 11),
+              ('net_amount_l', 12),
+              ('net_pct_l', 13),
+              ('net_amount_m', 14),
+              ('net_pct_m', 15),
+              ('net_amount_s', 16),
+              ('net_pct_s', 17),
+              )
+    '''
+
+
+class TestStrategy(bt.Strategy):
+    params = (
+        ("num", 3),
+        ('Volatility', 0),
+        ('rate', 3),  # 注意要有逗号!!
+    )
+
+    def log(self, txt, dt=None):
+        ''' Logging function for this strategy'''
+        dt = dt or self.datas[0].datetime.date(0)
+        # print('%s, %s' % (dt.isoformat(), txt))
+
+    def __init__(self):
+        # self.num = num
+        # self.Volatility = Volatility/100
+        # Keep a reference to the "close" line in the data[0] dataseries
+        self.pos_price = 0
+        self.dataclose = self.datas[0].close
+        self.dataopen = self.datas[0].open
+        self.high = self.datas[0].high
+        self.low = self.datas[0].low
+        self.volume = self.datas[0].volume
+        self.hl = self.datas[0].hl
+        self.dif = self.datas[0].dif
+        self.dea = self.datas[0].dea
+        self.macd = self.datas[0].macd
+        self.rsi_6 = self.datas[0].rsi_6
+        self.rsi_12 = self.datas[0].rsi_12
+        self.rsi_24 = self.datas[0].rsi_24
+        # self.change_pct = self.datas[0].change_pct
+        # self.net_amount_main = self.datas[0].net_amount_main
+        # self.net_pct_main = self.datas[0].net_pct_main
+        # self.net_amount_xl = self.datas[0].net_amount_xl
+        # self.net_pct_xl = self.datas[0].net_pct_xl
+        # self.net_amount_l = self.datas[0].net_amount_l
+        # self.net_pct_l = self.datas[0].net_pct_l
+        self.sma5 = btind.MovingAverageSimple(self.datas[0].close, period=5)
+        self.sma10 = btind.MovingAverageSimple(self.datas[0].close, period=10)
+        self.sma20 = btind.MovingAverageSimple(self.datas[0].close, period=20)
+        self.sma60 = btind.MovingAverageSimple(self.datas[0].close, period=60)
+
+    def notify_order(self, order):
+        """
+        订单状态处理
+
+        Arguments:
+            order {object} -- 订单状态
+        """
+        if order.status in [order.Submitted, order.Accepted]:
+            # 如订单已被处理,则不用做任何事情
+            return
+
+        # 检查订单是否完成
+        if order.status in [order.Completed]:
+            if order.isbuy():
+                self.buyprice = order.executed.price
+                self.buycomm = order.executed.comm
+            self.bar_executed = len(self)
+
+        # 订单因为缺少资金之类的原因被拒绝执行
+        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
+            pass
+            # self.log('Order Canceled/Margin/Rejected')
+
+        # 订单状态处理完成,设为空
+        self.order = None
+
+    def notify_trade(self, trade):
+        """
+        交易成果
+
+        Arguments:
+            trade {object} -- 交易状态
+        """
+        if not trade.isclosed:
+            return
+
+        # 显示交易的毛利率和净利润
+        # self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' % (trade.pnl, trade.pnlcomm))
+
+    def next(self):
+        # print(self.num,self.Volatility)
+        # Simply log the closing price of the series from the reference
+        # self.sma20[-2] < self.sma20[-1] < self.sma20[0] and self.sma10[-2] < self.sma10[-1] < self.sma10[0]
+        # and (self.sma5[-1] < self.sma10[-1])
+        # and (self.net_pct_l[0] > 10) and (self.net_pct_xl[0] > 3)  \
+        # and (self.net_amount_main[-1] > 0) and (self.net_amount_main[0] > 0)
+
+
+
+        if len(self) > self.params.num:
+            vola = self.params.Volatility / 100
+            rate = self.params.rate / 100
+            lowest = np.min(self.low.get(size=self.params.num))
+            highest = np.max(self.high.get(size=self.params.num))
+
+            #
+            # > self.sma5[-1]
+            # and (((lowest * (1 - vola)) < self.low[-2] < (lowest * (1 + vola))) or (
+            #         (lowest * (1 - vola)) < self.low[-1] < (lowest * (1 + vola)))) \
+            '''
+                        if (self.hl[-1] == 2 or self.hl[-1] == 1) and self.dataclose[0] > self.sma5[0]  \
+                    and self.dataclose[-1] > self.dataopen[-1] \
+                    and (self.sma10[-2] - self.sma5[-2]) < (self.sma10[-1] - self.sma5[-1]) \
+                    and self.low[-2] < self.sma5[-2] * (1 - rate) \
+                    and self.sma5[-1] < self.sma10[-1] < self.sma20[-1] < self.sma20[-2] < self.sma20[-3] < self.sma20[-4]:
+            '''
+            if (self.hl[0] == 1 or self.hl[0] == 2 or self.hl[0] == 3) \
+                    and (1-vola)*lowest < self.low[-1] < (1+vola)*lowest\
+                    and (self.sma10[-2] - self.sma5[-2]) < (self.sma10[-1] - self.sma5[-1]):
+            # if self.dataclose[0] > self.sma5[0] > self.sma10[0] and self.sma5[-1] < self.sma10[-1]:
+                self.order = self.buy()
+                self.pos_price = self.low[-1]
+
+            elif ((self.hl[0] == 4 or self.hl[0] == 5 or self.hl[0] == 6) and self.dataclose < self.sma5[0]) or self.dataclose[0] < self.pos_price:
+                    self.order = self.close()
+                    self.pos_price = 0
+
+
+            # elif (self.hl[0] == 5 or self.dataclose[0] < self.sma5[0]):
+            '''
+                        elif self.dataclose[0] < self.sma10[0] or self.sma5[0] < self.sma5[-1] or self.dataclose[0] < self.pos_price\
+                    or len(self) == (self.buflen()-1):
+            '''
+
+    def stop(self):
+        # pass
+        self.log(u'(MA趋势交易效果) Ending Value %.2f' % (self.broker.getvalue()))
+
+
+def err_call_back(err):
+    print(f'出错啦~ error:{str(err)}')
+    traceback.format_exc(err)
+
+
+def to_df(lt):
+    print('开始存数据')
+    df = pd.DataFrame(list(lt), columns=['周期', '波动率', 'MA5斜率', '盈利个数', '盈利比例', '总盈利', '平均盈利', '最大盈利',
+                               '最小盈利', '总亏损', '平均亏损', '最大亏损', '最小亏损', '盈亏对比'])
+    df.sort_values(by=['周期', '波动率', 'MA5斜率'], ascending=True, inplace=True)
+    df = df.reset_index(drop=True)
+    if platform.node() == 'DanieldeMBP.lan':
+        df.to_csv(f"/Users/daniel/Documents/策略/策略穷举{dt.now().strftime('%Y%m%d%H%m%S')}.csv", index=True, encoding='utf_8_sig', mode='w')
+    else:
+        df.to_csv(f"C:\Daniel\策略\策略穷举周期低点{dt.now().strftime('%Y%m%d%H%m%S' )}.csv", index=True, encoding='utf_8_sig', mode='w')
+    print(f'结果:{df}')
+
+
+def backtrader(list_date, table_list, result, result_change, result_change_fall, num, Volatility, rate, err_list):
+    print(f'{num}天波动率为{Volatility}%MA5斜率为{rate}', 'myPID is ', os.getpid())
+    sttime = dt.now()
+    engine = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/qmt_stocks_tech?charset=utf8')
+    for stock in table_list:
+        # print(stock)
+        stk_df = pd.read_sql_table(stock, engine)
+        stk_df.time = pd.to_datetime(stk_df.time)
+        stk_df = stk_df[stk_df['HL'] != '-']
+        try:
+            stk_df['HL'] = stk_df['HL'].map({'L': 1,
+                                             'LL': 2,
+                                             'L*': 3,
+                                             'H': 4,
+                                             'HH': 5,
+                                             'H*': 6,
+                                             '-': 7})
+        except BaseException:
+            print(f'{stock}数据不全,不做测试')
+        else:
+            if len(stk_df) > 60:
+                cerebro = bt.Cerebro()
+                cerebro.addstrategy(TestStrategy, num=num, Volatility=Volatility, rate=rate)
+                cerebro.addsizer(bt.sizers.FixedSize, stake=10000)
+                data = MyPandasData(dataname=stk_df,
+                                    fromdate=datetime.datetime(2017, 1, 1),
+                                    todate=datetime.datetime(2022, 10, 30),
+                                    datetime='time',
+                                    open='open_back',
+                                    close='close_back',
+                                    high='high_back',
+                                    low='low_back',
+                                    volume='volume_back',
+                                    hl='HL',
+                                    dif='dif',
+                                    dea='dea',
+                                    macd='macd',
+                                    rsi_6='rsi_6',
+                                    rsi_12='rsi_12',
+                                    rsi_24='rsi_24',
+                                    )
+                # print('取值完成')
+                cerebro.adddata(data, name=stock)
+                cerebro.broker.setcash(100000.0)
+                cerebro.broker.setcommission(0.005)
+                cerebro.addanalyzer(bt.analyzers.PyFolio)
+                # 策略执行前的资金
+                # print('启动资金: %.2f' % cerebro.broker.getvalue())
+                try:
+                    # 策略执行
+                    cerebro.run()
+                except IndexError as e:
+                    err_list.append(stock)
+                    # print(e)
+                else:
+                    if cerebro.broker.getvalue() > 100000.0:
+                        result_change.append(cerebro.broker.getvalue()-100000)
+                        result.append(stock)
+                        # print('recode!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
+                        # print(result)
+                    else:
+                        result_change_fall.append(cerebro.broker.getvalue()-100000)
+                        # if (cerebro.broker.getvalue()-100000) == np.min(result_change_fall):
+                        #     print(stock, (cerebro.broker.getvalue()-100000))
+                        # print('aaaaaaaaaaa')
+                        # print(result_change_fall)
+    print(f'计算总数={len(result)+len(result_change_fall)}')
+    if len(result) * len(result_change) * len(result_change_fall) != 0:
+        print(f'以{num}内最低值波动{Volatility}为支撑、MA5斜率为{rate}%,结果状态为:')
+        print('正盈利的个股为:', len(result), '成功率为:', len(result) / len(table_list))
+        print(
+            f'总盈利:{np.sum(result_change)} 平均盈利:{np.mean(result_change)/len(result)},最大盈利:{np.max(result_change)}, 最小盈利:{np.min(result_change)}')
+        print(
+            f'总亏损:{np.sum(result_change_fall)},平均亏损:{np.mean(result_change_fall)/len(result_change_fall)},最大亏损:{np.min(result_change_fall)} 最小亏损:{np.max(result_change_fall)}')
+
+        # '周期', '波动率', 'MA5斜率', '盈利个数', '盈利比例', '总盈利', '平均盈利', '最大盈利', '最小盈利', '总亏损', '平均亏损', '最大亏损', '最小亏损', '盈亏对比']
+        list_date.append([num, Volatility, rate, len(result), len(result) / len(table_list), np.nansum(result_change),
+                          np.nanmean(result_change), np.nanmax(result_change), np.min(result_change),
+                          np.nansum(result_change_fall), np.nanmean(result_change_fall),
+                          np.nanmin(result_change_fall), np.nanmax(result_change_fall), len(result_change)/len(result_change_fall)])
+        to_df(list_date)
+        endtime = dt.now()
+        print(f'{num}天波动率为{Volatility}%MA5斜率为{rate},myPID is {os.getpid()}.本轮耗时为{endtime - sttime}')
+    else:
+        print('阿欧', len(result), len(result_change), len(result_change_fall), num, Volatility, rate, err_list)
+        list_date.append([num, Volatility, rate, 0, len(result) / len(table_list), len(result),
+                          len(result), len(result), len(result), len(result), len(result), len(result), 0])
+    to_df(list_date)
+    # cerebro.plot()
+
+
+# df = pd.DataFrame(
+#     columns=['周期', '波动率', 'MA5斜率', '盈利个数', '盈利比例', '总盈利', '平均盈利', '最大盈利', '最小盈利', '总亏损',
+#              '平均亏损', '最大亏损', '最小亏损'])
+if __name__ == '__main__':
+    starttime = dt.now()
+    print(starttime)
+    pus = psutil.Process()
+    pus.cpu_affinity([23, 16, 17, 18, 19, 20, 21, 22])
+    # pus.cpu_affinity([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
+    # print(type(platform.node()))
+    # engine = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/hlfx?charset=utf8', poolclass=NullPool)
+
+    # stocks = pd.read_sql_query(
+    #                     'select value from MA5_1d', engine_hlfx)
+
+    fre = '1d'
+    db = pymysql.connect(host='localhost',
+                         user='root',
+                         port=3307,
+                         password='r6kEwqWU9!v3',
+                         database='qmt_stocks_tech')
+    cursor = db.cursor()
+    cursor.execute("show tables like '%%%s%%' " % fre)
+    table_list = [tuple[0] for tuple in cursor.fetchall()]
+    # print(table_list)
+    # table_list = table_list[0:500]
+    print(f'计算个股数为:{len(table_list)}')
+
+    list_date = mp.Manager().list()
+    thread_list = []
+    # pool = mp.Pool(processes=mp.cpu_count())
+    pool = mp.Pool(processes=8)
+    for num in range(20, 200, 20):
+        for Volatility in range(3, 11, 1):
+            for rate in range(1, 2, 1):
+                # step = math.ceil(len(table_list) / mp.cpu_count())
+                result = []
+                result_change = []
+                result_change_fall = []
+                err_list = []
+                print(f'{num}天波动率为{Volatility}%MA5斜率为{rate}')
+                # for i in range(0, len(table_list), step):
+                stattime = dt.now()
+                # thd = threading.local()
+                # print(i)
+                # p = mp.Process(target=backtrader, args=(df, table_list, result, result_change, result_change_fall,
+                #                                         num, Volatility, rate, err_list))
+                # thread_list.append(p)
+                pool.apply_async(func=backtrader,
+                                 args=(list_date, table_list, result, result_change, result_change_fall,
+                                       num, Volatility, rate, err_list,), error_callback=err_call_back)
+    pool.close()
+    pool.join()
+
+    edtime = dt.now()
+    print('总耗时:', edtime - starttime)
+    # df.to_csv(r'C:\Users\Daniel\Documents\策略穷举2.csv', index=True)

+ 346 - 0
backtrader/230505_bt.py

@@ -0,0 +1,346 @@
+import os
+import traceback
+import numpy as np
+from sqlalchemy import create_engine
+import pandas as pd
+import pymysql
+import backtrader as bt
+import backtrader.indicators as btind
+import datetime
+import math
+from datetime import datetime as dt
+import multiprocessing as mp
+from backtrader.feeds import PandasData
+import platform
+import psutil
+
+
+# import multiprocessing
+# import matplotlib
+
+
+class MyPandasData(PandasData):
+    lines = ('hl', 'dif', 'dea', 'macd', 'rsi_6', 'rsi_12', 'rsi_24',)
+    params = (('hl', 7),
+              ('dif', 8),
+              ('dea', 9),
+              ('macd', 10),
+              ('rsi_6', 11),
+              ('rsi_12', 12),
+              ('rsi_24', 13),
+              )
+    '''
+    lines = ('change_pct', 'net_amount_main', 'net_pct_main', 'net_amount_xl', 'net_pct_xl', 'net_amount_l', 'net_pct_l'
+             , 'net_amount_m', 'net_pct_m', 'net_amount_s', 'net_pct_s',)
+    params = (('change_pct', 7),
+              ('net_amount_main', 8),
+              ('net_pct_main', 9),
+              ('net_amount_xl', 10),
+              ('net_pct_xl', 11),
+              ('net_amount_l', 12),
+              ('net_pct_l', 13),
+              ('net_amount_m', 14),
+              ('net_pct_m', 15),
+              ('net_amount_s', 16),
+              ('net_pct_s', 17),
+              )
+    '''
+
+
+class TestStrategy(bt.Strategy):
+    params = (
+        ("num", 3),
+        ('Volatility', 0),
+        ('rate', 3),  # 注意要有逗号!!
+    )
+
+    def log(self, txt, dt=None):
+        ''' Logging function for this strategy'''
+        dt = dt or self.datas[0].datetime.date(0)
+        # print('%s, %s' % (dt.isoformat(), txt))
+
+    def __init__(self):
+        # self.num = num
+        # self.Volatility = Volatility/100
+        # Keep a reference to the "close" line in the data[0] dataseries
+        self.pos_price = 0
+        self.dataclose = self.datas[0].close
+        self.dataopen = self.datas[0].open
+        self.high = self.datas[0].high
+        self.low = self.datas[0].low
+        self.volume = self.datas[0].volume
+        self.hl = self.datas[0].hl
+        self.dif = self.datas[0].dif
+        self.dea = self.datas[0].dea
+        self.macd = self.datas[0].macd
+        self.rsi_6 = self.datas[0].rsi_6
+        self.rsi_12 = self.datas[0].rsi_12
+        self.rsi_24 = self.datas[0].rsi_24
+        # self.change_pct = self.datas[0].change_pct
+        # self.net_amount_main = self.datas[0].net_amount_main
+        # self.net_pct_main = self.datas[0].net_pct_main
+        # self.net_amount_xl = self.datas[0].net_amount_xl
+        # self.net_pct_xl = self.datas[0].net_pct_xl
+        # self.net_amount_l = self.datas[0].net_amount_l
+        # self.net_pct_l = self.datas[0].net_pct_l
+        self.sma5 = btind.MovingAverageSimple(self.datas[0].close, period=5)
+        self.sma10 = btind.MovingAverageSimple(self.datas[0].close, period=10)
+        self.sma20 = btind.MovingAverageSimple(self.datas[0].close, period=20)
+        self.sma60 = btind.MovingAverageSimple(self.datas[0].close, period=60)
+
+    def notify_order(self, order):
+        """
+        订单状态处理
+
+        Arguments:
+            order {object} -- 订单状态
+        """
+        if order.status in [order.Submitted, order.Accepted]:
+            # 如订单已被处理,则不用做任何事情
+            return
+
+        # 检查订单是否完成
+        if order.status in [order.Completed]:
+            if order.isbuy():
+                self.buyprice = order.executed.price
+                self.buycomm = order.executed.comm
+            self.bar_executed = len(self)
+
+        # 订单因为缺少资金之类的原因被拒绝执行
+        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
+            pass
+            # self.log('Order Canceled/Margin/Rejected')
+
+        # 订单状态处理完成,设为空
+        self.order = None
+
+    def notify_trade(self, trade):
+        """
+        交易成果
+
+        Arguments:
+            trade {object} -- 交易状态
+        """
+        if not trade.isclosed:
+            return
+
+        # 显示交易的毛利率和净利润
+        # self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' % (trade.pnl, trade.pnlcomm))
+
+    def next(self):
+        # print(self.num,self.Volatility)
+        # Simply log the closing price of the series from the reference
+        # self.sma20[-2] < self.sma20[-1] < self.sma20[0] and self.sma10[-2] < self.sma10[-1] < self.sma10[0]
+        # and (self.sma5[-1] < self.sma10[-1])
+        # and (self.net_pct_l[0] > 10) and (self.net_pct_xl[0] > 3)  \
+        # and (self.net_amount_main[-1] > 0) and (self.net_amount_main[0] > 0)
+
+        if len(self) > self.params.num:
+            vola = self.params.Volatility / 100
+            rate = self.params.rate / 100
+            lowest = np.min(self.low.get(size=self.params.num))
+            highest = np.max(self.high.get(size=self.params.num))
+
+            # > self.sma5[-1]
+            # and (((lowest * (1 - vola)) < self.low[-2] < (lowest * (1 + vola))) or (
+            #         (lowest * (1 - vola)) < self.low[-1] < (lowest * (1 + vola)))) \
+            if self.hl[-1] == 2 or self.hl[-1] == 1:
+                m = -2
+                self.order = self.buy()
+                self.pos_price = self.low[-1]
+
+                while True:
+                    if (self.hl[m] == 2 or self.hl[m] == 1) and self.macd[m] > self.macd[-1] \
+                            and self.dataclose[0] > self.sma5[0] \
+                            and self.dataclose[-1] > self.dataopen[-1] \
+                            and (self.sma10[-2] - self.sma5[-2]) < (self.sma10[-1] - self.sma5[-1]) \
+                            and self.low[-2] < self.sma5[-2] * (1 - rate) \
+                            and self.sma5[-1] < self.sma10[-1] < self.sma20[-1] < self.sma20[-2] < self.sma20[-3]\
+                            and lowest*(1-vola) < self.low[-1] < lowest * (1 + vola):
+                        self.order = self.buy()
+                        self.pos_price = self.low[-1]
+                        break
+                    m -= 1
+                    if m + len(self) == 2:
+                        break
+
+            # elif (self.hl[0] == 5 or self.dataclose[0] < self.sma5[0]):
+            elif self.dataclose[0] < self.sma5[0] or self.sma5[0] < self.sma5[-1] \
+                    or self.dataclose[0] < self.pos_price or self.high[0] > self.sma5[0] * (1 + vola):
+                self.order = self.close()
+                self.pos_price = 0
+
+    def stop(self):
+        # pass
+        self.log(u'(MA趋势交易效果) Ending Value %.2f' % (self.broker.getvalue()))
+
+
+def err_call_back(err):
+    print(f'出错啦~ error:{str(err)}')
+    traceback.format_exc(err)
+
+
+def to_df(lt):
+    print('开始存数据')
+    df = pd.DataFrame(list(lt),
+                      columns=['周期', '波动率', 'MA5斜率', '盈利个数', '盈利比例', '总盈利', '平均盈利', '最大盈利',
+                               '最小盈利', '总亏损', '平均亏损', '最大亏损', '最小亏损', '盈亏对比'])
+    df.sort_values(by=['周期', '波动率', 'MA5斜率'], ascending=True, inplace=True)
+    df = df.reset_index(drop=True)
+    if platform.node() == 'DanieldeMBP.lan':
+        df.to_csv(f"/Users/daniel/Documents/策略/策略穷举{dt.now().strftime('%Y%m%d%H%m%S')}.csv", index=True,
+                  encoding='utf_8_sig', mode='w')
+    else:
+        df.to_csv(f"C:\Daniel\策略\策略穷举_底分且均线扩散_rate低点{dt.now().strftime('%Y%m%d%H%m%S')}.csv", index=True, encoding='utf_8_sig',
+                  mode='w')
+    print(f'结果:{df}')
+
+
+def backtrader(list_date, table_list, result, result_change, result_change_fall, num, Volatility, rate, err_list):
+    print(f'{num}天波动率为{Volatility}%MA5斜率为{rate}', 'myPID is ', os.getpid())
+    sttime = dt.now()
+    engine = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/qmt_stocks_tech?charset=utf8',pool_size=4000)
+    for stock in table_list:
+        # print(stock)
+        stk_df = pd.read_sql_table(stock, engine.connect())
+        stk_df.time = pd.to_datetime(stk_df.time)
+        # stk_df = stk_df[stk_df['HL'] != '-']
+        try:
+            stk_df['HL'] = stk_df['HL'].map({'L': 1,
+                                             'LL': 2,
+                                             'L*': 3,
+                                             'H': 4,
+                                             'HH': 5,
+                                             'H*': 6,
+                                             '-': 7})
+        except BaseException:
+            print(f'{stock}数据不全,不做测试')
+        else:
+            if len(stk_df) > 60:
+                cerebro = bt.Cerebro()
+                cerebro.addstrategy(TestStrategy, num=num, Volatility=Volatility, rate=rate)
+                cerebro.addsizer(bt.sizers.FixedSize, stake=10000)
+                data = MyPandasData(dataname=stk_df,
+                                    fromdate=datetime.datetime(2017, 1, 1),
+                                    todate=datetime.datetime(2022, 10, 30),
+                                    datetime='time',
+                                    open='open_back',
+                                    close='close_back',
+                                    high='high_back',
+                                    low='low_back',
+                                    volume='volume_back',
+                                    hl='HL',
+                                    dif='dif',
+                                    dea='dea',
+                                    macd='macd',
+                                    rsi_6='rsi_6',
+                                    rsi_12='rsi_12',
+                                    rsi_24='rsi_24',
+                                    )
+                # print('取值完成')
+                cerebro.adddata(data, name=stock)
+                cerebro.broker.setcash(100000.0)
+                cerebro.broker.setcommission(0.005)
+                cerebro.addanalyzer(bt.analyzers.PyFolio)
+                # 策略执行前的资金
+                # print('启动资金: %.2f' % cerebro.broker.getvalue())
+                try:
+                    # 策略执行
+                    cerebro.run()
+                except IndexError as e:
+                    err_list.append(stock)
+                    # print(f'{num}天波动率为{Volatility}%MA5斜率为{rate}的{stock}错误')
+                    # print(e)
+                else:
+                    if cerebro.broker.getvalue() > 100000.0:
+                        result_change.append(cerebro.broker.getvalue() - 100000)
+                        result.append(stock)
+                        # print('recode!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
+                        # print(result)
+                    else:
+                        result_change_fall.append(cerebro.broker.getvalue() - 100000)
+                        # print('aaaaaaaaaaa')
+                        # print(result_change_fall)
+    print(f'计算总数={len(result) + len(result_change_fall)}')
+    if len(result) * len(result_change) * len(result_change_fall) != 0:
+        print(f'以{num}内最低值波动{Volatility}为支撑、MA5斜率为{rate}%,结果状态为:')
+        print('正盈利的个股为:', len(result), '成功率为:', len(result) / len(table_list))
+        print(
+            f'总盈利:{np.sum(result_change)} 平均盈利:{np.mean(result_change) / len(result)},最大盈利:{np.max(result_change)}, 最小盈利:{np.min(result_change)}')
+        print(
+            f'总亏损:{np.sum(result_change_fall)},平均亏损:{np.mean(result_change_fall) / len(result_change_fall)},最大亏损:{np.min(result_change_fall)} 最小亏损:{np.max(result_change_fall)}')
+
+        # '周期', '波动率', 'MA5斜率', '盈利个数', '盈利比例', '总盈利', '平均盈利', '最大盈利', '最小盈利', '总亏损', '平均亏损', '最大亏损', '最小亏损', '盈亏对比']
+        list_date.append([num, Volatility, rate, len(result), len(result) / len(table_list), np.nansum(result_change),
+                          np.nanmean(result_change), np.nanmax(result_change), np.min(result_change),
+                          np.nansum(result_change_fall), np.nanmean(result_change_fall),
+                          np.nanmin(result_change_fall), np.nanmax(result_change_fall),
+                          len(result_change) / len(result_change_fall)])
+        to_df(list_date)
+        endtime = dt.now()
+        print(f'{num}天波动率为{Volatility}%MA5斜率为{rate},myPID is {os.getpid()}.本轮耗时为{endtime - sttime}')
+    else:
+        print('阿欧', len(result), len(result_change), len(result_change_fall), num, Volatility, rate, err_list)
+        list_date.append([num, Volatility, rate, 0, len(result) / len(table_list), len(result),
+                          len(result), len(result), len(result), len(result), len(result), len(result), 0])
+    to_df(list_date)
+    # cerebro.plot()
+
+
+# df = pd.DataFrame(
+#     columns=['周期', '波动率', 'MA5斜率', '盈利个数', '盈利比例', '总盈利', '平均盈利', '最大盈利', '最小盈利', '总亏损',
+#              '平均亏损', '最大亏损', '最小亏损'])
+if __name__ == '__main__':
+    starttime = dt.now()
+    print(starttime)
+    pus = psutil.Process()
+    # pus.cpu_affinity([0, 1, 2, 3, 4, 5, 6, 7])
+    # pus.cpu_affinity([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
+    # print(type(platform.node()))
+    # engine = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/hlfx?charset=utf8', poolclass=NullPool)
+
+    # stocks = pd.read_sql_query(
+    #                     'select value from MA5_1d', engine_hlfx)
+
+    fre = '1d'
+    db = pymysql.connect(host='localhost',
+                         user='root',
+                         port=3307,
+                         password='r6kEwqWU9!v3',
+                         database='qmt_stocks_tech')
+    cursor = db.cursor()
+    cursor.execute("show tables like '%%%s%%' " % fre)
+    table_list = [tuple[0] for tuple in cursor.fetchall()]
+    # print(table_list)
+    # table_list = table_list[0:500]
+    print(f'计算个股数为:{len(table_list)}')
+
+    list_date = mp.Manager().list()
+    thread_list = []
+    # pool = mp.Pool(processes=mp.cpu_count())
+    pool = mp.Pool(processes=24)
+    for num in range(80, 200, 20):
+        for Volatility in range(3, 13, 1):
+            for rate in range(3, 13, 1):
+                # step = math.ceil(len(table_list) / mp.cpu_count())
+                result = []
+                result_change = []
+                result_change_fall = []
+                err_list = []
+                print(f'{num}天波动率为{Volatility}%MA5斜率为{rate}')
+                # for i in range(0, len(table_list), step):
+                stattime = dt.now()
+                # thd = threading.local()
+                # print(i)
+                # p = mp.Process(target=backtrader, args=(df, table_list, result, result_change, result_change_fall,
+                #                                         num, Volatility, rate, err_list))
+                # thread_list.append(p)
+                pool.apply_async(func=backtrader,
+                                 args=(list_date, table_list, result, result_change, result_change_fall,
+                                       num, Volatility, rate, err_list,), error_callback=err_call_back)
+    pool.close()
+    pool.join()
+
+    edtime = dt.now()
+    print('总耗时:', edtime - starttime)
+    # df.to_csv(r'C:\Users\Daniel\Documents\策略穷举2.csv', index=True)

+ 351 - 0
backtrader/230508_bt.py

@@ -0,0 +1,351 @@
+import os
+import traceback
+import numpy as np
+from sqlalchemy import create_engine
+import pandas as pd
+import pymysql
+import backtrader as bt
+import backtrader.indicators as btind
+import datetime
+import math
+from datetime import datetime as dt
+import multiprocessing as mp
+from backtrader.feeds import PandasData
+import platform
+import psutil
+
+
+# import multiprocessing
+# import matplotlib
+
+
+class MyPandasData(PandasData):
+    lines = ('hl', 'dif', 'dea', 'macd', 'rsi_6', 'rsi_12', 'rsi_24',)
+    params = (('hl', 7),
+              ('dif', 8),
+              ('dea', 9),
+              ('macd', 10),
+              ('rsi_6', 11),
+              ('rsi_12', 12),
+              ('rsi_24', 13),
+              )
+    '''
+    lines = ('change_pct', 'net_amount_main', 'net_pct_main', 'net_amount_xl', 'net_pct_xl', 'net_amount_l', 'net_pct_l'
+             , 'net_amount_m', 'net_pct_m', 'net_amount_s', 'net_pct_s',)
+    params = (('change_pct', 7),
+              ('net_amount_main', 8),
+              ('net_pct_main', 9),
+              ('net_amount_xl', 10),
+              ('net_pct_xl', 11),
+              ('net_amount_l', 12),
+              ('net_pct_l', 13),
+              ('net_amount_m', 14),
+              ('net_pct_m', 15),
+              ('net_amount_s', 16),
+              ('net_pct_s', 17),
+              )
+    '''
+
+
+class TestStrategy(bt.Strategy):
+    params = (
+        ("num", 3),
+        ('Volatility', 0),
+        ('rate', 3),  # 注意要有逗号!!
+    )
+
+    def log(self, txt, dt=None):
+        ''' Logging function for this strategy'''
+        dt = dt or self.datas[0].datetime.date(0)
+        # print('%s, %s' % (dt.isoformat(), txt))
+
+    def __init__(self):
+        # self.num = num
+        # self.Volatility = Volatility/100
+        # Keep a reference to the "close" line in the data[0] dataseries
+        self.pos_price = 0
+        self.dataclose = self.datas[0].close
+        self.dataopen = self.datas[0].open
+        self.high = self.datas[0].high
+        self.low = self.datas[0].low
+        self.volume = self.datas[0].volume
+        self.hl = self.datas[0].hl
+        self.dif = self.datas[0].dif
+        self.dea = self.datas[0].dea
+        self.macd = self.datas[0].macd
+        self.rsi_6 = self.datas[0].rsi_6
+        self.rsi_12 = self.datas[0].rsi_12
+        self.rsi_24 = self.datas[0].rsi_24
+        # self.change_pct = self.datas[0].change_pct
+        # self.net_amount_main = self.datas[0].net_amount_main
+        # self.net_pct_main = self.datas[0].net_pct_main
+        # self.net_amount_xl = self.datas[0].net_amount_xl
+        # self.net_pct_xl = self.datas[0].net_pct_xl
+        # self.net_amount_l = self.datas[0].net_amount_l
+        # self.net_pct_l = self.datas[0].net_pct_l
+        self.sma5 = btind.MovingAverageSimple(self.datas[0].close, period=5)
+        self.sma10 = btind.MovingAverageSimple(self.datas[0].close, period=10)
+        self.sma20 = btind.MovingAverageSimple(self.datas[0].close, period=20)
+        self.sma60 = btind.MovingAverageSimple(self.datas[0].close, period=60)
+
+    def notify_order(self, order):
+        """
+        订单状态处理
+
+        Arguments:
+            order {object} -- 订单状态
+        """
+        if order.status in [order.Submitted, order.Accepted]:
+            # 如订单已被处理,则不用做任何事情
+            return
+
+        # 检查订单是否完成
+        if order.status in [order.Completed]:
+            if order.isbuy():
+                self.buyprice = order.executed.price
+                self.buycomm = order.executed.comm
+            self.bar_executed = len(self)
+
+        # 订单因为缺少资金之类的原因被拒绝执行
+        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
+            pass
+            # self.log('Order Canceled/Margin/Rejected')
+
+        # 订单状态处理完成,设为空
+        self.order = None
+
+    def notify_trade(self, trade):
+        """
+        交易成果
+
+        Arguments:
+            trade {object} -- 交易状态
+        """
+        if not trade.isclosed:
+            return
+
+        # 显示交易的毛利率和净利润
+        # self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' % (trade.pnl, trade.pnlcomm))
+
+    def next(self):
+        # print(self.num,self.Volatility)
+        # Simply log the closing price of the series from the reference
+        # self.sma20[-2] < self.sma20[-1] < self.sma20[0] and self.sma10[-2] < self.sma10[-1] < self.sma10[0]
+        # and (self.sma5[-1] < self.sma10[-1])
+        # and (self.net_pct_l[0] > 10) and (self.net_pct_xl[0] > 3)  \
+        # and (self.net_amount_main[-1] > 0) and (self.net_amount_main[0] > 0)
+
+        if len(self) > self.params.num:
+            vola = self.params.Volatility / 100
+            rate = self.params.rate / 100
+            lowest = np.min(self.low.get(size=self.params.num))
+            highest = np.max(self.high.get(size=self.params.num))
+
+            # > self.sma5[-1]
+            # and (((lowest * (1 - vola)) < self.low[-2] < (lowest * (1 + vola))) or (
+            #         (lowest * (1 - vola)) < self.low[-1] < (lowest * (1 + vola)))) \
+            if self.hl[-1] == 2 or self.hl[-1] == 1:
+                m = -2
+                # self.order = self.buy()
+                # self.pos_price = self.low[-1]
+
+                while True:
+                    if (self.hl[m] == 2 or self.hl[m] == 1) and self.macd[m] > self.macd[-1] \
+                            and 0.99 * self.sma10[m] < self.sma5[m] < 1.01 * self.sma10[m] \
+                            and 0.99 * self.sma10[m-1] < self.sma5[m-1] < 1.01 * self.sma10[m-1] \
+                            and 0.99 * self.sma10[m-2] < self.sma5[m-2] < 1.01 * self.sma10[m-2] \
+                            and self.dataclose[0] > self.sma5[0] \
+                            and self.dataclose[-1] > self.dataopen[-1] \
+                            and self.volume[-1] > self.volume[-2] \
+                            and (self.sma10[-2] - self.sma5[-2]) < (self.sma10[-1] - self.sma5[-1]) \
+                            and self.low[-2] < self.sma5[-2] * (1 - rate) \
+                            and self.sma5[-1] < self.sma10[-1] < self.sma20[-1] < self.sma20[-2] < self.sma20[-3]:
+                        self.order = self.buy()
+                        self.pos_price = self.low[-1]
+                        break
+                    m -= 1
+                    if m + len(self) == 2:
+                        break
+
+            # elif (self.hl[0] == 5 or self.dataclose[0] < self.sma5[0]):
+            elif self.dataclose[0] < self.sma5[0] or self.sma5[0] < self.sma5[-1] \
+                    or self.dataclose[0] < self.pos_price or self.high[0] > self.sma5[0] * (1 + vola):
+                self.order = self.close()
+                self.pos_price = 0
+
+    def stop(self):
+        # pass
+        self.log(u'(MA趋势交易效果) Ending Value %.2f' % (self.broker.getvalue()))
+
+
+def err_call_back(err):
+    print(f'出错啦~ error:{str(err)}')
+    traceback.format_exc(err)
+
+
+def to_df(lt):
+    print('开始存数据')
+    df = pd.DataFrame(list(lt),
+                      columns=['周期', '波动率', 'MA5斜率', '盈利个数', '盈利比例', '总盈利', '平均盈利', '最大盈利',
+                               '最小盈利', '总亏损', '平均亏损', '最大亏损', '最小亏损', '盈亏对比'])
+    df.sort_values(by=['周期', '波动率', 'MA5斜率'], ascending=True, inplace=True)
+    df = df.reset_index(drop=True)
+    if platform.node() == 'DanieldeMBP.lan':
+        df.to_csv(f"/Users/daniel/Documents/策略/策略穷举-均线粘连后底分型{dt.now().strftime('%Y%m%d%H%m%S')}.csv", index=True,
+                  encoding='utf_8_sig', mode='w')
+    else:
+        df.to_csv(f"C:\Daniel\策略\策略穷举底分型_均线缠绕_只买一次{dt.now().strftime('%Y%m%d%H%m%S')}.csv", index=True,
+                  encoding='utf_8_sig', mode='w')
+    print(f'结果:, \n, {df}')
+
+
+def backtrader(list_date, table_list, result, result_change, result_change_fall, num, Volatility, rate, err_list):
+    print(f'{num}天波动率为{Volatility}%MA5斜率为{rate}', 'myPID is ', os.getpid())
+    sttime = dt.now()
+    engine = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/qmt_stocks_tech?charset=utf8',
+                           max_overflow=-1)
+    for stock in table_list:
+        # print(stock)
+        stk_df = pd.read_sql_table(stock, engine.connect())
+        stk_df.time = pd.to_datetime(stk_df.time)
+        # stk_df = stk_df[stk_df['HL'] != '-']
+        try:
+            stk_df['HL'] = stk_df['HL'].map({'L': 1,
+                                             'LL': 2,
+                                             'L*': 3,
+                                             'H': 4,
+                                             'HH': 5,
+                                             'H*': 6,
+                                             '-': 7})
+        except BaseException:
+            print(f'{stock}数据不全,不做测试')
+        else:
+            if len(stk_df) > 60:
+                cerebro = bt.Cerebro()
+                cerebro.addstrategy(TestStrategy, num=num, Volatility=Volatility, rate=rate)
+                cerebro.addsizer(bt.sizers.FixedSize, stake=10000)
+                data = MyPandasData(dataname=stk_df,
+                                    fromdate=datetime.datetime(2017, 1, 1),
+                                    todate=datetime.datetime(2022, 10, 30),
+                                    datetime='time',
+                                    open='open_back',
+                                    close='close_back',
+                                    high='high_back',
+                                    low='low_back',
+                                    volume='volume_back',
+                                    hl='HL',
+                                    dif='dif',
+                                    dea='dea',
+                                    macd='macd',
+                                    rsi_6='rsi_6',
+                                    rsi_12='rsi_12',
+                                    rsi_24='rsi_24',
+                                    )
+                # print('取值完成')
+                cerebro.adddata(data, name=stock)
+                cerebro.broker.setcash(100000.0)
+                cerebro.broker.setcommission(0.005)
+                cerebro.addanalyzer(bt.analyzers.PyFolio)
+                # 策略执行前的资金
+                # print('启动资金: %.2f' % cerebro.broker.getvalue())
+                try:
+                    # 策略执行
+                    cerebro.run()
+                except IndexError as e:
+                    err_list.append(stock)
+                    # print(f'{num}天波动率为{Volatility}%MA5斜率为{rate}的{stock}错误')
+                    # print(e)
+                else:
+                    if cerebro.broker.getvalue() > 100000.0:
+                        result_change.append(cerebro.broker.getvalue() - 100000)
+                        result.append(stock)
+                        # print('recode!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
+                        # print(result)
+                    elif cerebro.broker.getvalue() < 100000.0:
+                        result_change_fall.append(cerebro.broker.getvalue() - 100000)
+                        # print('aaaaaaaaaaa')
+                        # print(result_change_fall)
+    print(f'计算总数={len(result) + len(result_change_fall)}')
+    if len(result) * len(result_change) * len(result_change_fall) != 0:
+        print(f'以{num}内最低值波动{Volatility}为支撑、MA5斜率为{rate}%,结果状态为:')
+        print('正盈利的个股为:', len(result), '成功率为:', len(result) / len(table_list))
+        print(
+            f'总盈利:{np.sum(result_change)} 平均盈利:{np.mean(result_change) / len(result)},最大盈利:{np.max(result_change)}, 最小盈利:{np.min(result_change)}')
+        print(
+            f'总亏损:{np.sum(result_change_fall)},平均亏损:{np.mean(result_change_fall) / len(result_change_fall)},最大亏损:{np.min(result_change_fall)} 最小亏损:{np.max(result_change_fall)}')
+
+        # '周期', '波动率', 'MA5斜率', '盈利个数', '盈利比例', '总盈利', '平均盈利', '最大盈利', '最小盈利', '总亏损', '平均亏损', '最大亏损', '最小亏损', '盈亏对比']
+        list_date.append([num, Volatility, rate, len(result), len(result) / len(table_list), np.nansum(result_change),
+                          np.nanmean(result_change), np.nanmax(result_change), np.min(result_change),
+                          np.nansum(result_change_fall), np.nanmean(result_change_fall),
+                          np.nanmin(result_change_fall), np.nanmax(result_change_fall),
+                          len(result_change) / len(result_change_fall)])
+        to_df(list_date)
+        endtime = dt.now()
+        print(f'{num}天波动率为{Volatility}%MA5斜率为{rate},myPID is {os.getpid()}.本轮耗时为{endtime - sttime}')
+    else:
+        print('阿欧', len(result), len(result_change), len(result_change_fall), num, Volatility, rate, err_list)
+        list_date.append([num, Volatility, rate, 0, len(result) / len(table_list), len(result),
+                          len(result), len(result), len(result), len(result), len(result), len(result), 0])
+    to_df(list_date)
+    # cerebro.plot()
+
+
+# df = pd.DataFrame(
+#     columns=['周期', '波动率', 'MA5斜率', '盈利个数', '盈利比例', '总盈利', '平均盈利', '最大盈利', '最小盈利', '总亏损',
+#              '平均亏损', '最大亏损', '最小亏损'])
+if __name__ == '__main__':
+    starttime = dt.now()
+    print(starttime)
+    pus = psutil.Process()
+    # pus.cpu_affinity([23, 16, 17, 18, 19, 20, 21, 22])
+    # pus.cpu_affinity([0, 1, 2, 3, 4, 5, 6, 7])
+    # pus.cpu_affinity([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
+    # print(type(platform.node()))
+    # engine = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/hlfx?charset=utf8', poolclass=NullPool)
+
+    # stocks = pd.read_sql_query(
+    #                     'select value from MA5_1d', engine_hlfx)
+
+    fre = '1d'
+    db = pymysql.connect(host='localhost',
+                         user='root',
+                         port=3307,
+                         password='r6kEwqWU9!v3',
+                         database='qmt_stocks_tech')
+    cursor = db.cursor()
+    cursor.execute("show tables like '%%%s%%' " % fre)
+    table_list = [tuple[0] for tuple in cursor.fetchall()]
+    # print(table_list)
+    # table_list = table_list[0:500]
+    print(f'计算个股数为:{len(table_list)}')
+
+    list_date = mp.Manager().list()
+    thread_list = []
+    pool = mp.Pool(processes=mp.cpu_count())
+    # pool = mp.Pool(processes=8)
+    for num in range(60, 80, 20):
+        for Volatility in range(7, 13, 1):
+            for rate in range(3, 13, 1):
+                # step = math.ceil(len(table_list) / mp.cpu_count())
+                result = []
+                result_change = []
+                result_change_fall = []
+                err_list = []
+                print(f'{num}天波动率为{Volatility}%MA5斜率为{rate}')
+                # for i in range(0, len(table_list), step):
+                stattime = dt.now()
+                # thd = threading.local()
+                # print(i)
+                # p = mp.Process(target=backtrader, args=(df, table_list, result, result_change, result_change_fall,
+                #                                         num, Volatility, rate, err_list))
+                # thread_list.append(p)
+                pool.apply_async(func=backtrader,
+                                 args=(list_date, table_list, result, result_change, result_change_fall,
+                                       num, Volatility, rate, err_list,), error_callback=err_call_back)
+    pool.close()
+    pool.join()
+
+    edtime = dt.now()
+    print('总耗时:', edtime - starttime)
+    # df.to_csv(r'C:\Users\Daniel\Documents\策略穷举2.csv', index=True)

+ 113 - 0
docker.start.txt

@@ -6,3 +6,116 @@ docker run -itd --name mysql82 -p 3312:3306 -e MYSQL_ROOT_PASSWORD=r6kEwqWU9!v3
 mysqldump -uroot -pr6kEwqWU9!v3 -P3307 --databases qmt_stocks_whole >d:/qmt_stocks_whole.sql
 mysqldump -uroot -pr6kEwqWU9!v3 -P3307 --databases qmt_stocks_whole >d:/qmt_stocks_whole.sql
 
 
 # version order 1
 # version order 1
+
+
+docker run -itd --name mysql8 -p 3307:3306 -e MYSQL_ROOT_PASSWORD=r6kEwqWU9!v3 -v C:/docker_mysql/stock_data:/var/lib/mysql -v C:/docker_mysql/config/mysql.cnf:/etc/my.cnf daocloud.io/library/mysql:8.0.21
+
+docker run -itd --name mysql8033 -p 3308:3306 -e MYSQL_ROOT_PASSWORD=r6kEwqWU9!v3 -v C:/docker_mysql/0833:/var/lib/mysql -v C:/docker_mysql/conf:/etc/mysql mysql:8.0.33
+
+docker run -itd --name mysql8033 -p 3308:3306 -e MYSQL_ROOT_PASSWORD=r6kEwqWU9!v3 -v C:/docker_mysql/mysql.cnf:/etc/my.cnf mysql:8.0.33-debian
+
+docker run  -itd  -p 3307:3306 --name mysql8033 -e character-set-server=utf8mb4 --privileged=true  --restart unless-stopped -v C:/docker_mysql/stock_data:/var/lib/mysql  -e MYSQL_ROOT_PASSWORD=r6kEwqWU9!v3  -d mysql:8.0.33 --skip-log-bin --disable-log-bin --lower_case_table_names=1
+
+
+docker run  -itd  -p 3307:3306 --name mysql8033 -e character-set-server=utf8mb4 --privileged=true  --restart unless-stopped -v C:/docker_mysql/stock_data:/var/lib/mysql  -e MYSQL_ROOT_PASSWORD=r6kEwqWU9!v3  -d mysql:8.0.33 --lower_case_table_names=1 --skip-log-bin --disable-log-bin
+
+
+
+
+20230515
+docker run  -itd  -p 3307:3306 --name mysql8033 --privileged=true  --restart unless-stopped  -v C:/docker_mysql/stock_data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=r6kEwqWU9!v3  -d mysql:8.0.33
+docker run  -itd  -p 3309:3306 --name mysqltest -e character-set-server=utf8mb4 --privileged=true  --restart unless-stopped   -e MYSQL_ROOT_PASSWORD=r6kEwqWU9!v3  -d mysql:8.0.33 --skip-log-bin --disable-log-bin --log-error=/var/lib/mysql/err.log
+
+
+
+# For advice on how to change settings please see
+# http://dev.mysql.com/doc/refman/8.0/en/server-configuration-defaults.html
+
+[mysqld]
+#
+# Remove leading # and set to the amount of RAM for the most important data
+# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
+# innodb_buffer_pool_size = 128M
+#
+# Remove leading # to turn on a very important data integrity option: logging
+# changes to the binary log between backups.
+# log_bin
+#
+# Remove leading # to set options mainly useful for reporting servers.
+# The server defaults are faster for transactions and fast SELECTs.
+# Adjust sizes as needed, experiment to find the optimal values.
+# join_buffer_size = 128M
+# sort_buffer_size = 2M
+# read_rnd_buffer_size = 2M
+
+# Remove leading # to revert to previous value for default_authentication_plugin,
+# this will increase compatibility with older clients. For background, see:
+# https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_default_authentication_plugin
+# default-authentication-plugin=mysql_native_password
+skip-log-bin
+disable-log-bin
+skip-host-cache
+skip-name-resolve
+datadir=/var/lib/mysql
+socket=/var/run/mysqld/mysqld.sock
+secure-file-priv=/var/lib/mysql-files
+user=mysql
+max_connections=10000
+max_user_connections=5000
+character-set-server=utf8mb4
+thread_stack=4096k
+innodb_log_file_size=200M
+
+pid-file=/var/run/mysqld/mysqld.pid
+[client]
+socket=/var/run/mysqld/mysqld.sock
+character-set-server=utf8mb4
+!includedir /etc/mysql/conf.d/
+
+
+
+
+
+# For advice on how to change settings please see
+# http://dev.mysql.com/doc/refman/8.0/en/server-configuration-defaults.html
+
+[mysqld]
+#
+# Remove leading # and set to the amount of RAM for the most important data
+# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
+# innodb_buffer_pool_size = 128M
+#
+# Remove leading # to turn on a very important data integrity option: logging
+# changes to the binary log between backups.
+# log_bin
+#
+# Remove leading # to set options mainly useful for reporting servers.
+# The server defaults are faster for transactions and fast SELECTs.
+# Adjust sizes as needed, experiment to find the optimal values.
+# join_buffer_size = 128M
+# sort_buffer_size = 2M
+# read_rnd_buffer_size = 2M
+
+# Remove leading # to revert to previous value for default_authentication_plugin,
+# this will increase compatibility with older clients. For background, see:
+# https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_default_authentication_plugin
+# default-authentication-plugin=mysql_native_password
+skip-host-cache
+skip-name-resolve
+datadir=/var/lib/mysql
+socket=/var/run/mysqld/mysqld.sock
+secure-file-priv=/var/lib/mysql-files
+log_error=/var/lib/mysql/error.log
+user=mysql
+max_connections=2000
+max_user_connections=1000
+max_connect_errors=1000000
+thread_cache_size=300
+server-id = 1
+character-set-server = utf8mb4
+
+pid-file=/var/run/mysqld/mysqld.pid
+[client]
+socket=/var/run/mysqld/mysqld.sock
+
+!includedir /etc/mysql/conf.d/

+ 90 - 0
ttt.py

@@ -0,0 +1,90 @@
+m = 0
+# def mm(m):
+#     while True:
+#         print('m=', m)
+#         m = m + 1
+#         if m == 10:
+#             break
+#     return
+# print(mm(m))
+
+import pandas as pd
+import pymysql
+from sqlalchemy import create_engine, text
+import threading
+from datetime import datetime as dt
+import datetime
+from jqdatasdk.technical_analysis import *
+from xtquant import xtdata, xtconstant
+from xtquant.xttype import StockAccount
+from xtquant.xttrader import XtQuantTrader, XtQuantTraderCallback
+import time
+import math
+import multiprocessing as mp
+import os
+import psutil
+import traceback
+from apscheduler.schedulers.blocking import BlockingScheduler
+import sys
+
+# p = xtdata.get_instrument_detail('000001.sz')
+# print(p.get('UpStopPrice'))
+
+
+# stock = '000001.SZ'
+# engine_stock = create_engine('mysql+pymysql://root:r6kEwqWU9!v3@localhost:3307/qmt_stocks_whole?charset=utf8',
+#                              pool_size=5000, pool_recycle=50, max_overflow=-1)
+# df = pd.read_sql_query(text(
+#                 'select close_front, high_front from `%s_1d`' % stock), engine_stock.connect())
+#
+# print(df['close_front'].iloc[-1])
+# print(df['close_front'].iloc[-2])
+
+
+def sell_trader(data):
+    stock = '002645.SZ'
+    # print(data[stock][0]['close'])
+    print(xtdata.get_instrument_detail(stock).get('UpStopPrice'))
+
+    current_price = data[stock]['lastPrice']
+    print('aaa', current_price, data[stock]['time'])
+    print(data[stock])
+
+'''
+    if stock in data and can_use_volume != 0:
+        current_price = data[stock]['lastPrice']
+        open_price = data[stock]['open']
+        MA5 = ma(stock, 5, data)
+        MA5_1 = ma_1(stock, 5)
+        df = pd.read_sql_query(text(
+            'select close_front, high_front from `%s_1d`' % stock), engine_stock.connect())
+        print(f'{stock},持仓量为{can_use_volume}当前价:{current_price},MA5:{MA5},昨日MA5:{MA5_1},开始判断:')
+        if current_price == xtdata.get_instrument_detail(stock).get('UpStopPrice') \
+                or (df['close_front'].iloc[-1] == df['high_front'].iloc[-1]
+                    and df['close_front'].iloc[-1] / df['close_front'].iloc[-2] > 1.08):
+            continue
+        elif current_price < MA5 or MA5 < MA5_1:
+            print('卖出信号!!!!!!', stock, current_price)
+            order_id = xt_trader.order_stock(acc, stock, xtconstant.STOCK_SELL, can_use_volume,
+                                             xtconstant.LATEST_PRICE, 0, 'MA5策略', '低于MA5趋势向下')
+            print('价格:', current_price, open_price, MA5, MA5_1, '低于MA5趋势向下')
+            print(order_id, stock, can_use_volume)
+        elif current_price > MA5 * 1.07:
+            print('盈利乖离率超7%!!!!!!', stock, current_price)
+            order_id = xt_trader.order_stock(acc, stock, xtconstant.STOCK_SELL, can_use_volume,
+                                             xtconstant.LATEST_PRICE, 0, 'MA5策略', '盈利乖离率超7%')
+            print('价格:', current_price, open_price, MA5, MA5_1, '盈利乖离率超7%')
+            print(order_id, stock, can_use_volume)
+    else:
+        print(f'本轮没有持仓股票信息!')
+'''
+
+
+
+
+# xtdata.subscribe_quote('301125.SZ',callback=sell_trader)
+stocks = xtdata.get_stock_list_in_sector('沪深A股')
+xtdata.download_history_data2(stock_list=stocks, period='30m', start_time='', end_time='')
+print(stocks)
+seq = xtdata.subscribe_whole_quote(stocks, callback=sell_trader)
+xtdata.run()