async def _md_handler(self): async for pack in self.md_recv_chan: await self.md_send_chan.send({ "aid": "peek_message" }) for d in pack.get("data", []): TqApi._merge_diff(self.data, d, self.api._prototype, False)
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)))
class DemoCallback: def __init__(self): self.api = TqApi() self.quote = self.api.get_quote("SHFE.cu1805") def on_data_update(self): if self.quote.get("last_price", 0) > 1000: self.api.insert_order(symbol="SHFE.cu1805", direction="BUY", offset="OPEN", volume=1, limit_price=30000) def run(self): self.api.run(self.on_data_update)
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)
def scrawl_day_tick(date, ex): agg = agg_future_dayk() logging.info("start filter existed symbols") path = TICK_PATH logging.info("start getting tick data") api = TqApi(account=TqSim()) logging.info(ex + ": start getting tick") currentYearData = agg.getCurrentYearData(ex) currentYearData = currentYearData[currentYearData['date'] == date] pathpair = list( map( lambda x: (x[1].strftime('%Y%m%d') + "-" + x[0], x[0], datetime.utcfromtimestamp(x[1].timestamp())), currentYearData[['symbol', 'date']].values)) trading_dates = get_trading_calendar(security_type="future", exchange="shfe") tdates = {} for i in range(len(trading_dates)): if i > 0: tdates[datetime.strptime(trading_dates[i], '%Y%m%d')] = datetime.strptime( trading_dates[i - 1], '%Y%m%d') for i in pathpair: if i[1].startswith("sc"): continue the_dir1 = os.path.join(path, ex.upper(), str(i[2].year)) if not os.path.exists(the_dir1): os.makedirs(the_dir1) the_dir = os.path.join(path, ex.upper(), str(i[2].year), i[0] + ".csv.gz") the_dir2 = os.path.join(path, ex.upper(), str(i[2].year), i[0] + ".csv") # print(the_dir) if not os.path.exists(the_dir): td = DataDownloader(api, symbol_list=[ex.upper() + "." + i[1]], dur_sec=0, start_dt=tdates[i[2]] + timedelta(hours=17), end_dt=i[2] + timedelta(hours=15), csv_file_name=the_dir2) while not td.is_finished(): api.wait_update() # print("progress: tick:%.2f%%" % td.get_progress()) print("done:" + the_dir) logging.info(ex + ": complete getting tick")
class DemoTask: def __init__(self): self.api = TqApi() self.tm = TaskManager(self.api) def task_main(self): print("start") quote = self.api.get_quote("SHFE.cu1805") while True: wait_result = yield { "QUOTE_CHANGED": lambda: self.api.is_changing(quote), "TIMEOUT": 0.2, } if wait_result["QUOTE_CHANGED"]: print("Quote", quote) if wait_result["TIMEOUT"]: print("Timeout") def run(self): self.tm.start_task(self.task_main()) self.api.run()
def scrawl_single_tick(i, path, ex, tdates): the_dir1 = os.path.join(path, ex.upper(), str(i[2].year)) if not os.path.exists(the_dir1): os.makedirs(the_dir1) the_dir = os.path.join(path, ex.upper(), str(i[2].year), i[0] + ".csv.gz") the_dir2 = os.path.join(path, ex.upper(), str(i[2].year), i[0] + ".csv") if not os.path.exists(the_dir): print(the_dir) print(i) print(tdates[i[2]]) print(i[2]) api = TqApi(account=TqSim()) # api = TqApi(account=TqSim(),url="ws://192.168.56.1:7777") td = DataDownloader(api, symbol_list=[ex.upper() + "." + i[1]], dur_sec=0, start_dt=tdates[i[2]] + timedelta(hours=17), end_dt=i[2] + timedelta(hours=16), csv_file_name=the_dir2) while not td.is_finished(): api.wait_update() # print("progress: tick:%.2f%%" % td.get_progress()) print("done:" + the_dir) api.close() with open(the_dir2, 'rb') as f: with gzip.GzipFile(filename=the_dir2 + ".gz", mode='w', compresslevel=9) as gf: content = f.read() gf.write(content) os.remove(the_dir2) del td del api gc.collect()
class DemoSpread: def __init__(self): self.api = TqApi() self.tm = TaskManager(self.api) def task_main(self): print ("start") symbol_a = "SHFE.cu1805" symbol_b = "SHFE.cu1806" quote_a = self.api.get_quote(symbol_a) quote_b = self.api.get_quote(symbol_b) buy_open_spread = 50000 sell_close_spread = -70000 max_volume = 5 long_volume = 0 while True: wait_result = yield { "BUY_OPEN": lambda: long_volume == 0 and quote_a["ask_price1"] - quote_b["bid_price1"] < buy_open_spread, "SELL_CLOSE": lambda: long_volume > 0 and quote_a["bid_price1"] - quote_b["ask_price1"] > sell_close_spread, } if wait_result["BUY_OPEN"]: task_a = self.tm.start_task(make_order_until_all_matched(self.api, symbol=symbol_a, direction="BUY", offset="OPEN", volume=max_volume)) task_b = self.tm.start_task(make_order_until_all_matched(self.api, symbol=symbol_b, direction="SELL", offset="OPEN", volume=max_volume)) long_volume = max_volume if wait_result["SELL_CLOSE"]: task_a = self.tm.start_task(make_order_until_all_matched(self.api, symbol=symbol_a, direction="SELL", offset="CLOSE", volume=max_volume)) task_b = self.tm.start_task(make_order_until_all_matched(self.api, symbol=symbol_b, direction="BUY", offset="CLOSE", volume=max_volume)) long_volume = 0 wait_subtask_finish = yield { "ANY_TASK_ERROR": lambda: self.tm.get_error(task_a) or self.tm.get_error(task_b), "BOTH_TASK_FINSISH": lambda: self.tm.is_finish(task_a) and self.tm.is_finish(task_b), } if wait_subtask_finish["ANY_TASK_ERROR"]: break print ("finish") def run(self): self.tm.start_task(self.task_main()) self.api.run()
class DemoMa: def __init__(self): self.api = TqApi() self.tm = TaskManager(self.api) def task_main(self): print("start") symbol = "SHFE.cu1805" kline_serial_5s = self.api.get_kline_serial(symbol, 5) kline_serial_1m = self.api.get_kline_serial(symbol, 60) while True: yield { "KLINE_DATA_UPDATED": lambda: self.api.is_changing(kline_serial_1m) or self.api. is_changing(kline_serial_5s), } # 计算最近3根5秒线均价 average_price_15s = (kline_serial_5s[-1]["close"] + kline_serial_5s[-2]["close"] + kline_serial_5s[-3]["close"]) / 3 # 计算最近30根1分钟线均价 average_price_30m = sum(kline_serial_1m.close[-30:]) / 30 # 如果条件符合 print("average_price_15s", average_price_15s, "average_price_30m", average_price_30m) if average_price_15s > average_price_30m: self.api.insert_order(symbol=symbol, direction="BUY", offset="OPEN", volume=1, limit_price=5000) print("finish") def run(self): self.tm.start_task(self.task_main()) self.api.run()
def run(): #获取命令行参数 parser = argparse.ArgumentParser() parser.add_argument('--source_file') parser.add_argument('--instance_id') parser.add_argument('--instance_file') parser.add_argument('--tq_pid') args = parser.parse_args() TqMonitorThread(int(args.tq_pid)).start() # api api = TqApi(args.instance_id) try: sys.stdout = PrintWriter(api.send_chan, args.instance_id) # 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 Exception: # 获取用户代码中的参数表 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 if isinstance(v, datetime.date) or isinstance(v, datetime.time) \ or isinstance(v, int) or isinstance(v, float) or isinstance(v, str): 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": "desc", "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 __import__(module_name) except ModuleNotFoundError: logger.exception("加载策略文件失败") except IndentationError: logger.exception("策略文件缩进格式错误") except Exception as e: logger.exception("策略运行中遇到异常", exc_info=True) finally: if not api.loop.is_closed(): api.close()
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)
def dual_thrust(quote, klines): current_open = quote["open"] HH = max(klines.high[-Nday - 1:-1]) # N日最高价的最高价 HC = max(klines.close[-Nday - 1:-1]) # N日收盘价的最高价 LC = min(klines.close[-Nday - 1:-1]) # N日收盘价的最低价 LL = min(klines.low[-Nday - 1:-1]) # N日最低价的最低价 range = max(HH - LC, HC - LL) buy_line = current_open + range * K1 # 上轨 sell_line = current_open - range * K2 # 下轨 print("当前开盘价:", current_open, "\n上轨:", buy_line, "\n下轨:", sell_line) return buy_line, sell_line api = TqApi("SIM") quote = api.get_quote(symbol) klines = api.get_kline_serial(symbol, 24 * 60 * 60) # 86400使用日线 target_pos = TargetPosTask(api, symbol) buy_line, sell_line = dual_thrust(quote, klines) # 获取上下轨 while True: api.wait_update() if api.is_changing(klines[-1], "datetime") or api.is_changing( quote, "open"): # 新产生一根日线或开盘价发生变化: 重新计算上下轨 buy_line, sell_line = dual_thrust(quote, klines) if api.is_changing(quote, "last_price"): print("最新价变化", quote["last_price"], end=':') if quote["last_price"] > buy_line: # 高于上轨 print("高于上轨,目标持仓 多头3手")
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())
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'chengzhi' from datetime import datetime from tqsdk.api import TqApi from tqsdk.tools.downloader import DataDownloader import getopt, os, sys, re api = TqApi("SIM") # 下载从 2018-01-01 到 2018-06-01 的 cu1805,cu1807,IC1803 分钟线数据,所有数据按 cu1805 的时间对齐 # 例如 cu1805 夜盘交易时段, IC1803 的各项数据为 N/A # 例如 cu1805 13:00-13:30 不交易, 因此 IC1803 在 13:00-13:30 之间的K线数据会被跳过 # def incept_config(): config = {'output_dir': os.getcwd()} pattern = re.compile(r'\D*') def usage(): print(("Usage:%s [-s] [--data_source]" % sys.argv[0])) # print "-s --data_source, is the path of data file." print("-o --output_dir, is the output directory. optional.") print("-n --name, is the instrument id. optional.") print( "-g --granularities, default are 2,5,10,30,60 minutes, delimiter is a comma. optional." )
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())
def __init__(self): self.api = TqApi() self.quote = self.api.get_quote("SHFE.cu1805")
#!/usr/bin/env python # -*- coding: utf-8 -*- from tqsdk.api import TqApi api = TqApi("SIM") # 开仓两手并等待完成 order = api.insert_order(symbol="SHFE.rb1901", direction="BUY", offset="OPEN", limit_price=4310, volume=2) while order["status"] != "FINISHED": api.wait_update() print("已开仓") # 平今两手并等待完成 order = api.insert_order(symbol="SHFE.rb1901", direction="SELL", offset="CLOSETODAY", limit_price=3925, volume=2) while order["status"] != "FINISHED": api.wait_update() print("已平今") # 关闭api,释放相应资源 api.close()
def __init__(self): self.api = TqApi() self.tm = TaskManager(self.api)
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'chengzhi' from datetime import datetime from tqsdk.api import TqApi from tqsdk.tools.downloader import DataDownloader import getopt, os, sys, re url = 'ws://192.168.1.20:7777' api = TqApi("SIM", url) # 下载从 2018-01-01 到 2018-06-01 的 cu1805,cu1807,IC1803 分钟线数据,所有数据按 cu1805 的时间对齐 # 例如 cu1805 夜盘交易时段, IC1803 的各项数据为 N/A # 例如 cu1805 13:00-13:30 不交易, 因此 IC1803 在 13:00-13:30 之间的K线数据会被跳过 # def incept_config(): config = {'output_dir': os.getcwd()} pattern = re.compile(r'\D*') def usage(): print("Usage:%s [-s] [--data_source]" % sys.argv[0]) # print "-s --data_source, is the path of data file." print("-o --output_dir, is the output directory. optional.") print("-n --name, is the instrument id. optional.") print( "-g --granularities, default are 2,5,10,30,60 minutes, delimiter is a comma. optional." )
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'chengzhi' from tqsdk.api import TqApi import datetime api = TqApi("SIM") # 获得cu1812 tick序列的引用 ticks = api.get_tick_serial("SHFE.cu1812") # 获得cu1812 10秒K线的引用 klines = api.get_kline_serial("SHFE.cu1812", 10) while True: api.wait_update() # 判断整个tick序列是否有变化 if api.is_changing(ticks): # ticks[-1]返回序列中最后一个tick print("tick变化", ticks[-1]) # 判断最后一根K线的时间是否有变化,如果发生变化则表示新产生了一根K线 if api.is_changing(klines[-1], "datetime"): # datetime: 自unix epoch(1970-01-01 00:00:00 GMT)以来的纳秒数 print("新K线", datetime.datetime.fromtimestamp(klines[-1]["datetime"] / 1e9)) # 判断最后一根K线的收盘价是否有变化 if api.is_changing(klines[-1], "close"): # klines.close返回收盘价序列 print("K线变化", datetime.datetime.fromtimestamp(klines[-1]["datetime"] / 1e9), klines.close[-1])
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'chengzhi' from tqsdk.api import TqApi from tqsdk.lib import TargetPosTask ''' 如果当前价格大于10秒K线的MA15则开多仓 如果小于则平仓 ''' api = TqApi("SIM") # 获得 m1901 10秒K线的引用 klines = api.get_kline_serial("DCE.m1901", 10) # 创建 m1901 的目标持仓 task,该 task 负责调整 m1901 的仓位到指定的目标仓位 target_pos = TargetPosTask(api, "DCE.m1901") while True: api.wait_update() if api.is_changing(klines): ma = sum(klines.close[-15:]) / 15 print("最新价", klines.close[-1], "MA", ma) if klines.close[-1] > ma: print("最新价大于MA: 目标多头5手") # 设置目标持仓为多头5手 target_pos.set_target_volume(5) elif klines.close[-1] < ma: print("最新价小于MA: 目标空仓") # 设置目标持仓为空仓 target_pos.set_target_volume(0)
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'chengzhi' from tqsdk.api import TqApi ''' 如果当前价格大于10秒K线的MA15则开多仓 如果小于则平仓 ''' api = TqApi("SIM") # 获得 m1901 10秒K线的引用 klines = api.get_kline_serial("DCE.m1901", 10) # 判断开仓条件 while True: api.wait_update() if api.is_changing(klines): ma = sum(klines.close[-15:])/15 print("最新价", klines.close[-1], "MA", ma) if klines.close[-1] > ma: print("最新价大于MA: 市价开仓") api.insert_order(symbol="DCE.m1901", direction="BUY", offset="OPEN", volume=5) break # 判断平仓条件 while True: api.wait_update() if api.is_changing(klines): ma = sum(klines.close[-15:])/15 print("最新价", klines.close[-1], "MA", ma) if klines.close[-1] < ma:
#!/usr/bin/env python # -*- coding: utf-8 -*- from tqsdk.api import TqApi #时间转换函数 def timeChange(second=0, minute=0, hour=0): return second + minute * 60 + hour * 3600 api = TqApi("SIM") ticks = api.get_tick_serial("SHFE.rb1901") K_Line_one = api.get_kline_serial("SHFE.rb1901", timeChange(0, 3)) #负责大周期突破判断(时间自己判断) K_Line_two = api.get_kline_serial("SHFE.rb1901", timeChange(0, 15)) #负责止盈(时间自己判断) K_Line_three = api.get_kline_serial("SHFE.rb1901", timeChange(0, 0, 1)) #负责止损(时间自己判断) signBuy = 0 signSell = 0 cciValue = 0 sarLittleUp = [0] sarLittleDown = [0] sarBigUp = [0] sarBigDown = [0] #震荡指标(任意震荡指标 CCI默认n = 20) def CCI(n=20): TP = ((K_Line_one[-1]["close"] + K_Line_one[-1]["low"] +
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'chengzhi' from tqsdk.api import TqApi api = TqApi("SIM") # 获得 cu1812 的持仓引用,当持仓有变化时 position 中的字段会对应更新 position = api.get_position("SHFE.cu1812") # 获得资金账户引用,当账户有变化时 account 中的字段会对应更新 account = api.get_account() # 下单并返回委托单的引用,当该委托单有变化时 order 中的字段会对应更新 order = api.insert_order(symbol="SHFE.cu1812", direction="BUY", offset="OPEN", volume=5) while True: api.wait_update() if api.is_changing(order, ["status", "volume_orign", "volume_left"]): print("单状态: %s, 已成交: %d 手" % (order["status"], order["volume_orign"] - order["volume_left"])) if api.is_changing(position, "volume_long_today"): print("今多头: %d 手" % (position["volume_long_today"])) if api.is_changing(account, "available"): print("可用资金: %.2f" % (account["available"]))
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'yanqiong' from tqsdk.api import TqApi from tqsdk.lib import TargetPosTask ''' 连续3根阴线就做空,连续3根阳线就做多,否则空仓 ''' api = TqApi("SIM") # 设定连续多少根阳线/阴线 length = 3 # 获得 rb1901 10秒K线的引用, 长度为 length+1 klines = api.get_kline_serial("SHFE.rb1901", 10, data_length = length + 1) # 创建 rb1901 的目标持仓 task,该 task 负责调整 rb1901 的仓位到指定的目标仓位, offset_priority的用法详见文档 target_pos = TargetPosTask(api, "SHFE.rb1901", offset_priority="今昨开") while True: api.wait_update() # 只有在新创建出K线时才判断开平仓条件 if api.is_changing(klines[-1], "datetime"): # 将K线转为pandas.DataFrame, 跳过最后一根刚生成的K线 df = klines.to_dataframe()[:-1] # 比较收盘价和开盘价,判断是阳线还是阴线 # df["close"] 为收盘价序列, df["open"] 为开盘价序列, ">"(pandas.Series.gt) 返回收盘价是否大于开盘价的一个新序列 up = df["close"] > df["open"] down = df["close"] < df["open"] if all(up): print("连续阳线: 目标持仓 多头1手")
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'chengzhi' from tqsdk.api import TqApi from tqsdk.lib import TargetPosTask ''' 价差回归 当近月-远月的价差大于200时做空近月,做多远月 当价差小于150时平仓 ''' api = TqApi("SIM") quote_near = api.get_quote("SHFE.rb1810") quote_deferred = api.get_quote("SHFE.rb1901") # 创建 rb1810 的目标持仓 task,该 task 负责调整 rb1810 的仓位到指定的目标仓位 target_pos_near = TargetPosTask(api, "SHFE.rb1810") # 创建 rb1901 的目标持仓 task,该 task 负责调整 rb1901 的仓位到指定的目标仓位 target_pos_deferred = TargetPosTask(api, "SHFE.rb1901") while True: api.wait_update() if api.is_changing(quote_near) or api.is_changing(quote_deferred): spread = quote_near["last_price"] - quote_deferred["last_price"] print("当前价差:", spread) if spread > 200: print("目标持仓: 空近月,多远月") # 设置目标持仓为正数表示多头,负数表示空头,0表示空仓 target_pos_near.set_target_volume(-1) target_pos_deferred.set_target_volume(1) elif spread < 150: print("目标持仓: 空仓")
async def _ws_handler(self): async for pack in self.ws_recv_chan: for d in pack.get("data", []): TqApi._merge_diff(self.data, d, self.api.prototype)
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'chengzhi' from datetime import datetime from contextlib import closing from tqsdk.api import TqApi from tqsdk.tools.downloader import DataDownloader api = TqApi("SIM") # 下载从 2018-01-01凌晨6点 到 2018-06-01下午4点 的 cu1805 分钟线数据 kd = DataDownloader(api, symbol_list="SHFE.cu1805", dur_sec=60, start_dt=datetime(2018, 1, 1, 6, 0, 0), end_dt=datetime(2018, 6, 1, 16, 0, 0), csv_file_name="kline.csv") # 下载从 2018-05-01凌晨0点 到 2018-07-01凌晨0点 的 T1809 盘口Tick数据 td = DataDownloader(api, symbol_list="CFFEX.T1809", dur_sec=0, start_dt=datetime(2018, 5, 1), end_dt=datetime(2018, 7, 1), csv_file_name="tick.csv") # 使用with closing机制确保下载完成后释放对应的资源 with closing(api): while not kd.is_finished() or not td.is_finished(): api.wait_update() print("progress: kline: %.2f%% tick:%.2f%%" % (kd.get_progress(), td.get_progress()))
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'chengzhi' from tqsdk.api import TqApi api = TqApi("SIM") quote = api.get_quote("SHFE.cu1812") while True: api.wait_update() # 如果 cu1812 的任何字段有变化,is_changing就会返回 True if api.is_changing(quote): print(quote) # 只有当 cu1812 的最新价有变化,is_changing才会返回 True if api.is_changing(quote, "last_price"): print("最新价变化", quote["last_price"]) # 当 cu1812 的买1价/买1量/卖1价/卖1量中任何一个有变化,is_changing都会返回 True if api.is_changing( quote, ["ask_price1", "ask_volume1", "bid_price1", "bid_volume1"]): print("盘口变化", quote["ask_price1"], quote["ask_volume1"], quote["bid_price1"], quote["bid_volume1"])
class Y_Base: def __init__(self): self.api = TqApi() self.tm = TaskManager(self.api) def task_main(self): """ def test(): max_volume = 1 while True: wait_result = yield { "BUY_OPEN": False, "PRINT" : lambda: 1>0, "SELL_CLOSE": False, } if wait_result["BUY_OPEN"] : On_BUY(self, B_or_S, symbol, max_volume) if wait_result["SELL_CLOSE"]: #bors= "BUY" if self.b > price else "SELLL" On_CLOSE(self, B_or_S, symbol, max_volume) if wait_result["PRINT"]: pass """ pass """ def case_all(self, wait_result): if wait_result["BUY_OPEN"] : self.On_BUY(B_or_S, symbol, max_volume) if wait_result["SELL_CLOSE"]: #bors= "BUY" if self.b > price else "SELLL" self.On_CLOSE(B_or_S, symbol, max_volume) if wait_result["PRINT"]: pass """ def On_BUY(self, B_or_S, symbol, max_volume): #direction="BUY", offset="OPEN" if B_or_S == "BUY": task_a = self.tm.start_task(make_order_until_all_matched(self.api, symbol= symbol, direction="BUY", offset="OPEN", volume=max_volume)) #self.On_Open_Buy() 开多仓 else: task_b = self.tm.start_task(make_order_until_all_matched(self.api, symbol= symbol, direction="SELL", offset="OPEN", volume=max_volume)) #self.On_Open_Sell() 开空仓 return task_a if B_or_S == "BUY" else task_b def On_CLOSE(self, B_or_S, symbol, max_volume): """ #direction="SELL", offset="CLOSE" BorS: "SELL" 多单持仓 (卖入平仓) "BUY" 空单持仓 (买入平仓) """ if B_or_S == "SELL": """ "SELL" 原持仓为多单,平仓 "BUY" 原持仓为空单, 平仓 """ task_a = self.tm.start_task(make_order_until_all_matched(self.api, symbol= symbol, direction="SELL", offset="CLOSE", volume=max_volume)) #self.On_Close_Buy() else: #self.On_Close_Sell() task_b = self.tm.start_task(make_order_until_all_matched(self.api, symbol= symbol, direction="BUY", offset="CLOSE", volume=max_volume)) return task_a if B_or_S == "SELL" else task_b def max_min_ave_ks(self,symbol, m, n = 20): """ Args: symbol (str): 指定合约代码. m (int): K线数据周期,以秒为单位。 Returns: Dict:{ min: n个数据的最小值 max: n个数据的最高值 ave: n个数据的平均值 } 使用: def task_main(self): quote_a = self.api.get_quote(self.symbol_a) dictk = self.max_min_ave_ks(self.symbol_a,60 * 60 * 24,20) while True: wait_result = yield { "BUY_OPEN": lambda: (long_volume == 0 and quote_a["ask_price1"] >= dictk['max']), "PRINT" : lambda: 1>0, "SELL_CLOSE": lambda: (long_volume > 0 and quote_a["ask_price1"] <= dictk['min']), } if wait_result["PRINT"]: print(......) if wait_result["BUY_OPEN"] : print("开仓 ", quote_a["ask_price1"] ) task_a = self.On_BUY("BUY",self.symbol_a,max_volume) if wait_result["SELL_CLOSE"]: print("平仓 ", quote_a["bid_price1"]) task_a = self.On_CLOSE("SELL",self.symbol_a,max_volume) ........ """ kline_serial_1ks = self.api.get_kline_serial(self.symbol_a, m) return { 'min' : min(kline_serial_1ks.low[-n:]), 'max' : max(kline_serial_1ks.high[-n:]), 'ave' : sum(kline_serial_1ks.close[-n:])/n, } def run(self): self.tm.start_task(self.task_main()) self.api.run()