示例#1
0
def link_tq(api):
    """
    处理py进程到天勤的连接

    根据天勤提供的命令行参数, 决定 TqApi 工作方式

    * 直接调整api的参数

    TqApi运行过程中的一批信息主动发送到天勤显示

    * 进程启动和停止
    * set_chart_data 指令全部发往天勤绘图
    * 所有 log / print 信息传递一份
    * exception 发送一份
    * 所有报单/成交记录抄送一份

    :return: (account, backtest, md_url)
    """
    from tqsdk.api import TqChan, TqAccount
    from tqsdk.sim import TqSim
    # 解析命令行参数
    parser = argparse.ArgumentParser()
    # 天勤连接基本参数
    parser.add_argument('--_action', type=str, required=False)
    parser.add_argument('--_tq_pid', type=int, required=False)
    parser.add_argument('--_tq_url', type=str, required=False)
    # action==run时需要这几个
    parser.add_argument('--_broker_id', type=str, required=False)
    parser.add_argument('--_account_id', type=str, required=False)
    parser.add_argument('--_password', type=str, required=False)
    # action==backtest时需要这几个
    parser.add_argument('--_start_dt', type=str, required=False)
    parser.add_argument('--_end_dt', type=str, required=False)
    # action==mdreplay时需要这几个
    parser.add_argument('--_ins_url', type=str, required=False)
    parser.add_argument('--_md_url', type=str, required=False)
    args, unknown = parser.parse_known_args()

    # 非天勤启动时直接返回
    if args._action is None:
        return None, None
    if args._tq_pid is None:
        raise Exception("_tq_pid 参数缺失")
    if args._tq_url is None:
        raise Exception("_tq_url 参数缺失")
    if args._action == "run" and (not args._broker_id or not args._account_id
                                  or not args._password):
        raise Exception("run 必要参数缺失")
    if args._action == "backtest" and (not args._start_dt or not args._end_dt):
        raise Exception("backtest 必要参数缺失")
    if args._action == "mdreplay" and (not args._ins_url or not args._md_url):
        raise Exception("mdreplay 必要参数缺失")

    # 监控天勤进程存活情况
    TqMonitorThread(args._tq_pid).start()

    # 建立到天勤进程的连接
    tq_send_chan, tq_recv_chan = TqChan(api), TqChan(api)  # 连接到天勤的channel
    api.create_task(api._connect(args._tq_url, tq_send_chan,
                                 tq_recv_chan))  # 启动到天勤客户端的连接

    # 根据运行模式分别执行不同的初始化任务
    if args._action == "run":
        instance = SingleInstance(args._account_id)
        api._account = TqAccount(args._broker_id, args._account_id,
                                 args._password)
        api._backtest = None
        dt_func = lambda: int(datetime.datetime.now().timestamp() * 1e9)
        tq_send_chan.send_nowait({
            "aid": "register_instance",
            "instance_id": instance.instance_id,
            "full_path": get_self_full_name(),
            "instance_pid": os.getpid(),
            "instance_type": "RUN",
            "broker_id": args._broker_id,
            "account_id": args._account_id,
            "password": args._password,
        })
    elif args._action == "backtest":
        instance = SingleInstance("%s-%s" % (args._start_dt, args._end_dt))
        if not isinstance(api._account, TqSim):
            api._account = TqSim()
        from tqsdk.backtest import TqBacktest
        start_date = datetime.datetime.strptime(args._start_dt, '%Y%m%d')
        end_date = datetime.datetime.strptime(args._end_dt, '%Y%m%d')
        api._backtest = TqBacktest(start_dt=start_date, end_dt=end_date)
        dt_func = lambda: api._account._get_current_timestamp()
        tq_send_chan.send_nowait({
            "aid": "register_instance",
            "instance_id": instance.instance_id,
            "full_path": get_self_full_name(),
            "instance_pid": os.getpid(),
            "instance_type": "BACKTEST",
            "start_dt": args._start_dt,
            "end_dt": args._end_dt,
        })
    elif args._action == "mdreplay":
        instance = SingleInstance(args._account_id)
        api._account = TqSim(account_id=args._account_id)
        api._backtest = None
        api._md_url = args._md_url
        api._ins_url = args._ins_url
        dt_func = lambda: api._account._get_current_timestamp()
        tq_send_chan.send_nowait({
            "aid": "register_instance",
            "instance_id": instance.instance_id,
            "full_path": get_self_full_name(),
            "instance_pid": os.getpid(),
            "instance_type": "RUN",
            "account_id": "SIM",
        })
    else:
        raise Exception("_action 参数异常")

    # print输出, exception信息转发到天勤
    logger = logging.getLogger("TQ")
    logger.setLevel(logging.INFO)
    logger.addHandler(LogHandlerChan(tq_send_chan,
                                     dt_func=dt_func))  # log输出到天勤接口
    sys.stdout = PrintWriterToLog(logger)  # print信息转向log输出
    sys.excepthook = partial(exception_handler, api,
                             sys.excepthook)  # exception信息转向log输出

    # 向api注入监控任务, 将账户交易信息主动推送到天勤
    api.create_task(account_watcher(api, dt_func, tq_send_chan))
    return tq_send_chan, tq_recv_chan
示例#2
0
def run():
    #获取命令行参数
    parser = argparse.ArgumentParser()
    parser.add_argument('--source_file')
    parser.add_argument('--instance_id')
    parser.add_argument('--instance_file')
    args = parser.parse_args()

    # api
    api = TqApi(TqAccount("", args.instance_id, ""),
                url="ws://127.0.0.1:7777/" + args.instance_id)
    with closing(api):
        # log
        logger = logging.getLogger("TQ")
        logger.setLevel(logging.INFO)
        th = TqRunLogger(api.send_chan, args.instance_id)
        th.setLevel(logging.INFO)
        logger.addHandler(th)

        try:
            #加载策略文件
            file_path, file_name = os.path.split(args.source_file)
            sys.path.insert(0, file_path)
            module_name = file_name[:-3]

            param_list = []
            # 加载或输入参数
            try:
                # 从文件读取参数表
                with open(args.instance_file, "rt") as param_file:
                    instance = json.load(param_file)
                    param_list = instance.get("param_list", [])
            except IOError:
                # 获取用户代码中的参数表
                def _fake_api_for_param_list(*args, **kwargs):
                    m = sys.modules[module_name]
                    for k, v in m.__dict__.items():
                        if k.upper() != k:
                            continue
                        param_list.append([k, v])
                    raise Exception()

                tqsdk.TqApi = _fake_api_for_param_list
                try:
                    importlib.import_module(module_name)
                except Exception:
                    pass

                param_list = input_param(param_list)
                if param_list is None:
                    return
                with open(args.instance_file, "wt") as param_file:
                    json.dump(
                        {
                            "instance_id": args.instance_id,
                            "strategy_file_name": args.source_file,
                            "desc": json.dumps(param_list),
                            "param_list": param_list,
                        }, param_file)
            api.send_chan.send_nowait({
                "aid": "status",
                "instance_id": args.instance_id,
                "status": "RUNNING",
                "desc": json.dumps(param_list)
            })

            # 拉起实例并直接执行
            def _fake_api_for_launch(*args, **kwargs):
                m = sys.modules[module_name]
                for k, v in param_list:
                    m.__dict__[k] = v
                return api

            tqsdk.TqApi = _fake_api_for_launch
            importlib.import_module(module_name)

        except ModuleNotFoundError:
            logger.exception("加载策略文件失败")
        except IndentationError:
            logger.exception("策略文件缩进格式错误")
        except Exception as e:
            logger.exception("策略运行中遇到异常", exc_info=True)