Exemplo n.º 1
0
    def __init__(self, start_dt, end_dt):
        """
        创建天勤回测类

        Args:
            start_dt (date/datetime): 回测起始时间, 如果类型为 date 则指的是交易日, 如果为 datetime 则指的是具体时间点

            end_dt (date/datetime): 回测结束时间, 如果类型为 date 则指的是交易日, 如果为 datetime 则指的是具体时间点
        """
        if isinstance(start_dt, datetime):
            self.current_dt = int(start_dt.timestamp() * 1e9)
        elif isinstance(start_dt, date):
            self.current_dt = TqApi._get_trading_day_start_time(
                int(
                    datetime(start_dt.year, start_dt.month,
                             start_dt.day).timestamp()) * 1000000000)
        else:
            raise Exception(
                "回测起始时间(start_dt)类型 %s 错误, 请检查 start_dt 数据类型是否填写正确" %
                (type(start_dt)))
        if isinstance(end_dt, datetime):
            self.end_dt = int(end_dt.timestamp() * 1e9)
        elif isinstance(end_dt, date):
            self.end_dt = TqApi._get_trading_day_end_time(
                int(
                    datetime(end_dt.year, end_dt.month,
                             end_dt.day).timestamp()) * 1000000000)
        else:
            raise Exception("回测结束时间(end_dt)类型 %s 错误, 请检查 end_dt 数据类型是否填写正确" %
                            (type(end_dt)))
Exemplo n.º 2
0
    def __init__(self, start_dt, end_dt):
        """
        创建天勤回测类

        Args:
            start_dt (date/datetime): 回测起始时间, 如果类型为 date 则指的是交易日, 如果为 datetime 则指的是具体时间点

            end_dt (date/datetime): 回测结束时间, 如果类型为 date 则指的是交易日, 如果为 datetime 则指的是具体时间点
        """
        if isinstance(start_dt, datetime):
            self.current_dt = int(start_dt.timestamp()*1e9)
        else:
            self.current_dt = TqApi._get_trading_day_start_time(int(datetime(start_dt.year, start_dt.month, start_dt.day).timestamp())*1000000000)
        if isinstance(end_dt, datetime):
            self.end_dt = int(end_dt.timestamp()*1e9)
        else:
            self.end_dt = TqApi._get_trading_day_end_time(int(datetime(end_dt.year, end_dt.month, end_dt.day).timestamp())*1000000000)
Exemplo n.º 3
0
 async def _gen_serial(self, ins, dur):
     """k线/tick 序列的 async generator, yield 出来的行情数据带有时间戳, 因此 _send_diff 可以据此归并"""
     # 先定位左端点, focus_datetime 是 lower_bound ,这里需要的是 upper_bound
     # 因此将 view_width 和 focus_position 设置成一样,这样 focus_datetime 所对应的 k线刚好位于屏幕外
     chart_info = {
         "aid":
         "set_chart",
         "chart_id":
         TqApi._generate_chart_id("backtest", ins, dur // 1000000000),
         "ins_list":
         ins,
         "duration":
         dur,
         "view_width":
         8964,
         "focus_datetime":
         int(self.current_dt),
         "focus_position":
         8964,
     }
     chart = TqApi._get_obj(self.data, ["charts", chart_info["chart_id"]])
     current_id = None  # 当前数据指针
     serial = TqApi._get_obj(
         self.data,
         ["klines", ins, str(dur)] if dur != 0 else ["ticks", ins])
     async with TqChan(self.api, last_only=True) as update_chan:
         serial["_listener"].add(update_chan)
         chart["_listener"].add(update_chan)
         await self.md_send_chan.send(chart_info.copy())
         try:
             async for _ in update_chan:
                 if not (chart_info.items() <= TqApi._get_obj(
                         chart, ["state"]).items()):
                     # 当前请求还没收齐回应, 不应继续处理
                     continue
                 left_id = chart.get("left_id", -1)
                 right_id = chart.get("right_id", -1)
                 last_id = serial.get("last_id", -1)
                 if (left_id == -1 and right_id == -1) or last_id == -1:
                     # 定位信息还没收到, 或数据序列还没收到
                     continue
                 if self.data.get("mdhis_more_data", True):
                     self.data["_listener"].add(update_chan)
                     continue
                 else:
                     self.data["_listener"].discard(update_chan)
                 if current_id is None:
                     current_id = max(left_id, 0)
                 while True:
                     if current_id > last_id:
                         # 当前 id 已超过 last_id
                         return
                     if current_id - chart_info.get("left_kline_id",
                                                    left_id) > 5000:
                         # 当前 id 已超出订阅范围, 需重新订阅后续数据
                         chart_info["left_kline_id"] = current_id
                         chart_info.pop("focus_datetime", None)
                         chart_info.pop("focus_position", None)
                         await self.md_send_chan.send(chart_info.copy())
                     if current_id > right_id:
                         break
                     item = serial["data"].get(str(current_id), {}).copy()
                     del item["_path"]
                     del item["_listener"]
                     if dur == 0:
                         diff = {
                             "ticks": {
                                 ins: {
                                     "last_id": current_id,
                                     "data": {
                                         str(current_id): item,
                                         str(current_id - 8964): None,
                                     }
                                 }
                             }
                         }
                         if item["datetime"] > self.end_dt:  # 超过结束时间
                             return
                         yield item[
                             "datetime"], diff, self._get_quotes_from_tick(
                                 item)
                     else:
                         diff = {
                             "klines": {
                                 ins: {
                                     str(dur): {
                                         "last_id": current_id,
                                         "data": {
                                             str(current_id): {
                                                 "datetime":
                                                 item["datetime"],
                                                 "open": item["open"],
                                                 "high": item["open"],
                                                 "low": item["open"],
                                                 "close": item["open"],
                                                 "volume": 0,
                                                 "open_oi": item["open_oi"],
                                                 "close_oi":
                                                 item["open_oi"],
                                             },
                                             str(current_id - 8964): None,
                                         }
                                     }
                                 }
                             }
                         }
                         timestamp = item[
                             "datetime"] if dur < 86400000000000 else TqApi._get_trading_day_start_time(
                                 item["datetime"])
                         if timestamp > self.end_dt:  # 超过结束时间
                             return
                         yield timestamp, diff, None
                         diff = {
                             "klines": {
                                 ins: {
                                     str(dur): {
                                         "data": {
                                             str(current_id): item,
                                         }
                                     }
                                 }
                             }
                         }
                         timestamp = item[
                             "datetime"] + dur - 1000 if dur < 86400000000000 else TqApi._get_trading_day_end_time(
                                 item["datetime"])
                         if timestamp > self.end_dt:  # 超过结束时间
                             return
                         yield timestamp, diff, self._get_quotes_from_kline(
                             self.data["quotes"][ins], timestamp, item)
                     current_id += 1
         finally:
             # 释放chart资源
             chart_info["ins_list"] = ""
             await self.md_send_chan.send(chart_info.copy())
Exemplo n.º 4
0
    def __init__(self, api, symbol_list, dur_sec, start_dt, end_dt,
                 csv_file_name):
        """
        创建历史数据下载器实例

        Args:
            api (TqApi): TqApi实例,该下载器将使用指定的api下载数据

            symbol_list (str/list of str): 需要下载数据的合约代码,当指定多个合约代码时将其他合约按第一个合约的交易时间对齐

            dur_sec (int): 数据周期,以秒为单位。例如: 1分钟线为60,1小时线为3600,日线为86400,Tick数据为0

            start_dt (date/datetime): 起始时间, 如果类型为 date 则指的是交易日, 如果为 datetime 则指的是具体时间点

            end_dt (date/datetime): 结束时间, 如果类型为 date 则指的是交易日, 如果为 datetime 则指的是具体时间点

            csv_file_name (str): 输出csv的文件名

        Example::

            from datetime import datetime, date
            from contextlib import closing
            from tqsdk import TqApi, TqSim
            from tqsdk.tools import DataDownloader

            api = TqApi(TqSim())
            download_tasks = {}
            # 下载从 2018-01-01 到 2018-09-01 的 SR901 日线数据
            download_tasks["SR_daily"] = DataDownloader(api, symbol_list="CZCE.SR901", dur_sec=24*60*60,
                                start_dt=date(2018, 1, 1), end_dt=date(2018, 9, 1), csv_file_name="SR901_daily.csv")
            # 下载从 2017-01-01 到 2018-09-01 的 rb主连 5分钟线数据
            download_tasks["rb_5min"] = DataDownloader(api, symbol_list="*****@*****.**", dur_sec=5*60,
                                start_dt=date(2017, 1, 1), end_dt=date(2018, 9, 1), csv_file_name="rb_5min.csv")
            # 下载从 2018-01-01凌晨6点 到 2018-06-01下午4点 的 cu1805,cu1807,IC1803 分钟线数据,所有数据按 cu1805 的时间对齐
            # 例如 cu1805 夜盘交易时段, IC1803 的各项数据为 N/A
            # 例如 cu1805 13:00-13:30 不交易, 因此 IC1803 在 13:00-13:30 之间的K线数据会被跳过
            download_tasks["cu_min"] = DataDownloader(api, symbol_list=["SHFE.cu1805", "SHFE.cu1807", "CFFEX.IC1803"], dur_sec=60,
                                start_dt=datetime(2018, 1, 1, 6, 0 ,0), end_dt=datetime(2018, 6, 1, 16, 0, 0), csv_file_name="cu_min.csv")
            # 下载从 2018-05-01凌晨0点 到 2018-06-01凌晨0点 的 T1809 盘口Tick数据
            download_tasks["T_tick"] = DataDownloader(api, symbol_list=["CFFEX.T1809"], dur_sec=0,
                                start_dt=datetime(2018, 5, 1), end_dt=datetime(2018, 6, 1), csv_file_name="T1809_tick.csv")
            # 使用with closing机制确保下载完成后释放对应的资源
            with closing(api):
                while not all([v.is_finished() for v in download_tasks.values()]):
                    api.wait_update()
                    print("progress: ", { k:("%.2f%%" % v.get_progress()) for k,v in download_tasks.items() })
        """
        self.api = api
        if isinstance(start_dt, datetime):
            self.start_dt_nano = int(start_dt.timestamp() * 1e9)
        else:
            self.start_dt_nano = TqApi._get_trading_day_start_time(
                int(
                    datetime(start_dt.year, start_dt.month,
                             start_dt.day).timestamp()) * 1000000000)
        if isinstance(end_dt, datetime):
            self.end_dt_nano = int(end_dt.timestamp() * 1e9)
        else:
            self.end_dt_nano = TqApi._get_trading_day_end_time(
                int(
                    datetime(end_dt.year, end_dt.month,
                             end_dt.day).timestamp()) * 1000000000)
        self.current_dt_nano = self.start_dt_nano
        self.symbol_list = symbol_list if isinstance(symbol_list,
                                                     list) else [symbol_list]
        self.dur_nano = dur_sec * 1000000000
        if self.dur_nano == 0 and len(self.symbol_list) != 1:
            raise Exception("Tick序列不支持多合约")
        self.csv_file_name = csv_file_name
        self.task = self.api.create_task(self._download_data())