class TqsdkClient(LocalClient): def __init__(self, **kwargs): super().__init__() self.p = Thread(target=self.init_api, args=()) self.p.start() self.api = None def init_api(self): self.api = TqApi() while True: self.api.wait_update() def get(self, *argsm, **params): """ 调用他们的历史数据 """ # tick数据 if params.get("level") == "tick": del params['level'] temp = self.api.get_tick_serial(*argsm, **params) return temp # 分钟线数据 if params.get("level") != "tick": return self.api.get_kline_serial(*argsm, **params) def set(self): pass
def test_get_kline_serial(self): """ 获取K线数据 """ # 预设服务器端响应 self.mock.run("test_md_basic_get_kline_serial.script") # 测试: 获取K线数据 TqApi.RD = random.Random(1) api = TqApi(_ins_url=self.ins_url, _td_url=self.td_url, _md_url=self.md_url) klines = api.get_kline_serial("SHFE.cu1909", 10) self.assertEqual(klines.iloc[-1].close, 47580.0) self.assertEqual(klines.iloc[-1].id, 660788) self.assertEqual(klines.iloc[-2].id, 660787) self.assertEqual(klines.iloc[-1].datetime, 1.56861719e+18) self.assertEqual(klines.iloc[-1].open, 47580) self.assertEqual(klines.iloc[-1].volume, 0.0) self.assertEqual(klines.iloc[-1].open_oi, 6940.0) self.assertEqual(klines.iloc[-1].duration, 10) # 其他取值方式 self.assertEqual(klines.duration.iloc[-1], 10) self.assertEqual(klines.iloc[-1]["duration"], 10) self.assertEqual(klines["duration"].iloc[-1], 10) # 报错测试 self.assertRaises(Exception, api.get_kline_serial, "SHFE.au1999", 10) self.assertRaises(AttributeError, klines.iloc[-1].__getattribute__, "dur") self.assertRaises(KeyError, klines.iloc[-1].__getitem__, "dur") api.close()
def test_get_kline_serial(self): """ 获取K线数据 """ # 预设服务器端响应 dir_path = os.path.dirname(os.path.realpath(__file__)) self.mock.run( os.path.join(dir_path, "log_file", "test_md_basic_get_kline_serial.script.lzma")) # 测试: 获取K线数据 utils.RD = random.Random(1) api = TqApi(_ins_url=self.ins_url_2019_07_03, _td_url=self.td_url, _md_url=self.md_url) klines = api.get_kline_serial("SHFE.cu1909", 10) self.assertEqual(klines.iloc[-1].close, 47580.0) self.assertEqual(klines.iloc[-1].id, 660788) self.assertEqual(klines.iloc[-2].id, 660787) self.assertEqual(klines.iloc[-1].datetime, 1.56861719e+18) self.assertEqual(klines.iloc[-1].open, 47580) self.assertEqual(klines.iloc[-1].volume, 0.0) self.assertEqual(klines.iloc[-1].open_oi, 6940.0) self.assertEqual(klines.iloc[-1].duration, 10) # 其他取值方式 self.assertEqual(klines.duration.iloc[-1], 10) self.assertEqual(klines.iloc[-1]["duration"], 10) self.assertEqual(klines["duration"].iloc[-1], 10) # 报错测试 self.assertRaises(Exception, api.get_kline_serial, "SHFE.au1999", 10) self.assertRaises(AttributeError, klines.iloc[-1].__getattribute__, "dur") self.assertRaises(KeyError, klines.iloc[-1].__getitem__, "dur") api.close()
def sync_db(): api = TqApi() queryset = DatabaseSqlite() for item in sync_list: try: df = api.get_kline_serial( symbol=item["symbol_tq"], duration_seconds=item.get( "duration_seconds", default_settings["duration_seconds"]), data_length=item.get("data_length", default_settings["data_length"])) queryset.update_from_df(df=df, exchange=item["exchange"], symbol=item["symbol_db"], interval=item.get( "interval", default_settings["interval"]), time_handler_type="nanometre") except Exception as error: print(f"{item['symbol_tq']} 同步失败,原因:{error}") queryset.close() print("\n列表同步完毕!!!")
def run_tianqin_code(port): try: api = TqApi(web_gui="127.0.0.1:" + port) klines = api.get_kline_serial("SHFE.au1910", 24 * 60 * 60) ma = MA(klines, 30) # 使用tqsdk自带指标函数计算均线 while True: api.wait_update() except Exception as e: api.close()
def run_tianqin_code(port, queue): try: ins_url = "http://127.0.0.1:5000/t/md/symbols/2019-07-03.json" api = TqApi(_ins_url=ins_url, web_gui="127.0.0.1:" + port) queue.put("webready") klines = api.get_kline_serial("SHFE.au1910", 24 * 60 * 60) ma = MA(klines, 30) # 使用tqsdk自带指标函数计算均线 while True: api.wait_update() except Exception as e: api.close()
class TqSdkClient(LocalClient): def __init__(self, **kwargs): self.api = TqApi() def get(self, **params): """ 调用他们的历史数据 """ if params.get("level") == "tick": return self.api.get_tick_serial(*self._parse_params(params)) if params.get("level") != "tick": return self.api.get_kline_serial(*self._parse_params(params)) def _parse_params(self, params): """ 将参数解析为tq可以理解的方式 都需要返回一个*args """ level = params.get("level") local_symbol = params.get("local_symbol") length = params.get("length") if level != "tick": return [local_symbol, self.get_seconds(level), length] return [local_symbol, length] @staticmethod def get_seconds(level) -> int: """ 将level转换到秒 * level: 数据等级 """ min_r = r"(\d{1,2})min" hour_r = r"(\d{1,2})h" day_r = r"(\d{1,2})day" if "min" in level: try: return int(re.match(min_r, level).group(1)) * 60 except Exception: raise ValueError("你输入的level数据等级存在问题, 请检查是否符合1min这样的格式") if "h" in level: try: return int(re.match(hour_r, level).group(1)) * 3600 except Exception: raise ValueError("你输入的level数据等级存在问题, 请检查是否符合1min这样的格式") if "day" in level: try: return int(re.match(day_r, level).group(1)) * 3600 * 24 except Exception: raise ValueError("你输入的level数据等级存在问题, 请检查是否符合1day这样的格式")
def test_wait_update_1(self): """ 若未连接天勤时修改了K线字段,则不应发送set_chart_data指令到服务器 (即不能调用api.py中_process_serial_extra_array()); 否则导致与服务器断连 related issue: #146 """ # 预设服务器端响应 dir_path = os.path.dirname(os.path.realpath(__file__)) self.mock.run(os.path.join(dir_path, "log_file", "test_func_wait_update_1.script")) # 测试 api = TqApi(_ins_url=self.ins_url, _td_url=self.td_url, _md_url=self.md_url) TqApi.RD = random.Random(4) klines = api.get_kline_serial("SHFE.cu1911", 10) klines["ma"] = MA(klines, 15) # 测试语句 deadline = time.time() + 10 while api.wait_update(deadline=deadline): pass api.close()
def run_tianqin_code(port): try: api = TqApi(backtest=TqBacktest(start_dt=date(2018, 5, 5), end_dt=date(2018, 5, 10)), web_gui="127.0.0.1:" + port) klines = api.get_kline_serial("DCE.m1901", 5 * 60, data_length=15) target_pos = TargetPosTask(api, "DCE.m1901") while True: api.wait_update() if api.is_changing(klines): ma = sum(klines.close.iloc[-15:]) / 15 if klines.close.iloc[-1] > ma: target_pos.set_target_volume(5) elif klines.close.iloc[-1] < ma: target_pos.set_target_volume(0) except BacktestFinished as e: while True: api.wait_update() except Exception as e: api.close()
def main(argv=None): """ 测试脚本内容 """ if argv is None: argv = sys.argv # acc = TqAccount("快期模拟", config_se['simAccoutName'], \ # config_se['simAccoutName']) acc = TqSim() api = TqApi(acc) # try: # 执行策略方法 kline = api.get_kline_serial("SHFE.cu1903", 7 * 24 * 60 * 60) for i in range(200): kline.iloc[i, 0] = datetime.fromtimestamp(kline.iloc[i, 0] / 1000000000) print(kline.iloc[-20:-1, :]) # Strategy(api, "xxx").aberration() api.close()
def backtest(): """ 回测耗时测试 """ # 预设服务器端响应 dir_path = os.path.dirname(os.path.realpath(__file__)) log_path = os.path.join(dir_path, "log_file", "test_backtest.script.lzma") times = [] for i in range(20): mock = MockServer() md_url = "ws://127.0.0.1:5100/" td_url = "ws://127.0.0.1:5200/" mock.run(log_path) utils.RD = random.Random(4) try: start = datetime.datetime.now() backtest = TqBacktest( start_dt=datetime.datetime(2019, 8, 10), end_dt=datetime.datetime(2019, 9, 11)) api = TqApi(backtest=backtest, _ins_url=self.ins_url_2019_07_03, _md_url=md_url, _td_url=td_url) symbol = "DCE.m2005" klines = api.get_kline_serial(symbol, duration_seconds=60) while True: api.wait_update() except BacktestFinished: delta = datetime.datetime.now() - start self.assertLess(delta.seconds, 60) times.append(delta.seconds + delta.microseconds * 1e-6) # print(delta.seconds + delta.microseconds * 1e-6) api.close() mock.close() print(times) print(sum(times))
def run_tianqin_code(port, queue): try: ins_url = "http://127.0.0.1:5000/t/md/symbols/2019-07-03.json" api = TqApi(backtest=TqBacktest(start_dt=date(2019, 7, 10), end_dt=date(2019, 7, 20)), _ins_url=ins_url, web_gui="127.0.0.1:" + port) queue.put("webready") klines = api.get_kline_serial("DCE.m1912", 5 * 60, data_length=15) target_pos = TargetPosTask(api, "DCE.m1912") while True: api.wait_update() if api.is_changing(klines): ma = sum(klines.close.iloc[-15:]) / 15 if klines.close.iloc[-1] > ma: target_pos.set_target_volume(5) elif klines.close.iloc[-1] < ma: target_pos.set_target_volume(0) except BacktestFinished as e: while True: api.wait_update() except Exception as e: api.close()
fh.setLevel(logging.DEBUG) # 输出到file的log等级的开关 ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) # 输出到console的log等级的开关 # 第三步,定义handler的输出格式 formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s") fh.setFormatter(formatter) ch.setFormatter(formatter) # 第四步,将logger添加到handler里面 logger.addHandler(fh) logger.addHandler(ch) api = TqApi(TqSim()) #time_slot_start = datetime.time(START_HOUR, START_MINUTE) # 计划交易时段起始时间点 #time_slot_end = datetime.time(END_HOUR, END_MINUTE) # 计划交易时段终点时间点 klines = api.get_kline_serial(SYMBOL, TIME_CELL, data_length=int(10 * 60 * 60 / TIME_CELL)) target_pos = TargetPosTask(api, SYMBOL) position = api.get_position(SYMBOL) # 持仓信息 quote = api.get_quote(SYMBOL) logger.info("start %s daily strategy for %s!"%(c, SYMBOL)) current_volume = 0 # 记录持仓量 traded_volume = 0 cur_trading_date = '' # 交易预警参数 k_count = 0 signal_interval = 10 short_price = 0.0
from tqsdk import TqApi, TqSim, TargetPosTask,TqAccount,TqBacktest from tqsdk.ta import MA,SMA,SAR from datetime import date from tqsdk import TqReplay from tqsdk.tafunc import ma data_length = 200 # k线数据长度 SYMBOL = "SHFE.rb2005" # 合约代码 api = TqApi(TqAccount("simnow", "090828", "jimc1230",front_broker='9999',front_url='tcp://180.168.146.187:10100'),web_gui="0.0.0.0:9876")#web_gui="0.0.0.0:9876" # api = TqApi(backtest=TqBacktest(start_dt=date(2020, 3,10), end_dt=date(2020, 3, 19)),web_gui="0.0.0.0:9876")#"0.0.0.0:9876"#回测模式 # api = TqApi(backtest = TqReplay(date(2020,3,18)),web_gui="0.0.0.0:9876")#复盘模式 print("策略开始运行") # "duration_seconds=60"为一分钟线, 日线的duration_seconds参数为: 24*60*60 klines = api.get_kline_serial(SYMBOL, duration_seconds=1*60, data_length=data_length) #收盘后不可查 target_pos = TargetPosTask(api, SYMBOL) position = api.get_position(SYMBOL)#指定一个品种查看持仓相关信息 account = api.get_account()#获取用户账户资金信息 while True: api.wait_update() if api.is_changing(klines.iloc[-1], "datetime"): # 产生新k线:重新计算SMA klines["ma5"]=ma(klines["close"], 5) klines["ma10"]=ma(klines["close"], 10) klines["ma89"]=ma(klines["close"], 89)
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'chengzhi' import datetime from tqsdk import TqApi, TqSim from tqsdk.ta import * api = TqApi(TqSim()) # 获得 cu1906 10秒K线的引用 klines = api.get_kline_serial("SHFE.cu1906", 10, data_length=3000) print("K线时间", datetime.datetime.fromtimestamp(klines.iloc[-1]["datetime"] / 1e9)) print(klines) print("ATR", ATR(klines, 26)) print("BIAS", BIAS(klines, 6)) print("BOLL", BOLL(klines, 3, 5)) print("DMI", DMI(klines, 14, 6)) print("KDJ", KDJ(klines, 9, 3, 3)) print("MA", MA(klines, 3)) print("MACD", MACD(klines, 20, 35, 10)) print("SAR", SAR(klines, 4, 0.02, 0.2)) api.close()
#!usr/bin/env python3 #-*- coding:utf-8 -*- #!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'chengzhi' from datetime import date from tqsdk import TqApi, TqReplay, TargetPosTask ''' 复盘 2019-11-12 如果当前价格大于5分钟K线的MA15则开多仓,如果小于则平仓 ''' # 在创建 api 实例时传入 TqReplay 就会进入复盘模式, 同时打开 web_gui api = TqApi(backtest=TqReplay(date(2019, 11, 12)), web_gui=True) # 获得 m1901 5分钟K线的引用 klines = api.get_kline_serial("SHFE.cu2001", 5 * 60, data_length=15) # 创建 m1901 的目标持仓 task,该 task 负责调整 m1901 的仓位到指定的目标仓位 target_pos = TargetPosTask(api, "SHFE.cu2001") while True: api.wait_update() if api.is_changing(klines): ma = sum(klines.close.iloc[-15:]) / 15 print("最新价", klines.close.iloc[-1], "MA", ma) if klines.close.iloc[-1] > ma: print("最新价大于MA: 目标多头5手") # 设置目标持仓为多头5手 target_pos.set_target_volume(5) elif klines.close.iloc[-1] < ma: print("最新价小于MA: 目标空仓") # 设置目标持仓为空仓
#STEP1:交易信号汇总 trading_date = '' parser = argparse.ArgumentParser() parser.add_argument('--SYMBOL') args = parser.parse_args() if args.SYMBOL != None: SYMBOL = args.SYMBOL else: SYMBOL = "DCE.i2005" #STEP2:log logger.info("Starting yiboduo strategy for: %s"%SYMBOL) api = TqApi(TqSim()) klines = api.get_kline_serial(SYMBOL, duration_seconds=60*60*24, data_length=20) #ticks = api.get_tick_serial(SYMBOL) quote = api.get_quote(SYMBOL) while True: api.wait_update() # 跟踪log信息,日k数据会产生两个信号:一个是开盘时,另一个时收盘;如果想根据收盘k线分析前期趋势,用第二个信号 # 这样就没有之前认为必须开盘才能分析之前所存在的趋势型机会了。 # 实盘是只要14:59或盘后任何时间触发运行即可,一次退出; # 想尾盘参与策略型机会则收盘前运行回报策略型机会,次日择机参与则盘后任何时间运行即可 if api.is_changing(klines): df = klines.to_dataframe() #logger.info("DATE: %s, close: %f"%(get_market_day(klines[-1]["datetime"]), klines[-1]["close"])) trading_date = bases.get_market_day(klines[-1]["datetime"])
from contextlib import closing import numpy as np import pandas as pd from tqsdk import TqApi from technical_indicators import SMA # import seaborn as sns # sns.set_style('white') SYMBOL = 'CFFEX.IF1904' api = TqApi('SIM') klines = api.get_kline_serial(SYMBOL, duration_seconds=60) quote = api.get_quote(SYMBOL) def wave(klines, w=1, X=20): ys = pd.Series(data=klines.close[-100:-1], index=[ str(dt.datetime.fromtimestamp(i / 1e9)) for i in klines.datetime[-100:-1] ]) l = len(ys) ls_ix = ys.index.tolist() ls_ix_peaks = [] ls_ix_bottoms = [] for i in range(l - w - 1, w - 1, -1):
__author__ = 'chengzhi' from datetime import date from contextlib import closing from tqsdk import TqApi, TqSim, TqBacktest, TargetPosTask ''' 如果当前价格大于5分钟K线的MA15则开多仓 如果小于则平仓 回测从 2018-05-01 到 2018-10-01 ''' # 在创建 api 实例时传入 TqBacktest 就会进入回测模式 api = TqApi(TqSim(), backtest=TqBacktest(start_dt=date(2018, 5, 1), end_dt=date(2018, 10, 1))) # 获得 m1901 5分钟K线的引用 klines = api.get_kline_serial("DCE.m1901", 5 * 60, data_length=15) # 创建 m1901 的目标持仓 task,该 task 负责调整 m1901 的仓位到指定的目标仓位 target_pos = TargetPosTask(api, "DCE.m1901") # 使用with closing机制确保回测完成后释放对应的资源 with closing(api): while True: api.wait_update() if api.is_changing(klines): ma = sum(klines.close.iloc[-15:]) / 15 print("最新价", klines.close.iloc[-1], "MA", ma) if klines.close.iloc[-1] > ma: print("最新价大于MA: 目标多头5手") # 设置目标持仓为多头5手 target_pos.set_target_volume(5) elif klines.close.iloc[-1] < ma:
class Turtle: def __init__(self, account, symbol, donchian_channel_open_position=20, donchian_channel_stop_profit=10, atr_day_length=20, max_risk_ratio=0.5): self.account = account # 交易账号 self.symbol = symbol # 合约代码 self.donchian_channel_open_position = donchian_channel_open_position # 唐奇安通道的天数周期(开仓) self.donchian_channel_stop_profit = donchian_channel_stop_profit # 唐奇安通道的天数周期(止盈) self.atr_day_length = atr_day_length # ATR计算所用天数 self.max_risk_ratio = max_risk_ratio # 最高风险度 self.state = { "position": 0, # 本策略净持仓数(正数表示多头,负数表示空头,0表示空仓) "last_price": float("nan"), # 上次调仓价 } self.n = 0 # 平均真实波幅(N值) self.unit = 0 # 买卖单位 self.donchian_channel_high = 0 # 唐奇安通道上轨 self.donchian_channel_low = 0 # 唐奇安通道下轨 self.api = TqApi(self.account) self.quote = self.api.get_quote(self.symbol) # 由于ATR是路径依赖函数,因此使用更长的数据序列进行计算以便使其值稳定下来 kline_length = max(donchian_channel_open_position + 1, donchian_channel_stop_profit + 1, atr_day_length * 5) self.klines = self.api.get_kline_serial(self.symbol, 24 * 60 * 60, data_length=kline_length) self.account = self.api.get_account() self.target_pos = TargetPosTask(self.api, self.symbol, init_pos=self.state["position"]) def recalc_paramter(self): # 平均真实波幅(N值) self.n = ATR(self.klines, self.atr_day_length)["atr"].iloc[-1] # 买卖单位 self.unit = int((self.account.balance * 0.01) / (self.quote.volume_multiple * self.n)) # 唐奇安通道上轨:前N个交易日的最高价 self.donchian_channel_high = max( self.klines.high[-self.donchian_channel_open_position - 1:-1]) # 唐奇安通道下轨:前N个交易日的最低价 self.donchian_channel_low = min( self.klines.low[-self.donchian_channel_open_position - 1:-1]) print("唐其安通道上下轨: %f, %f" % (self.donchian_channel_high, self.donchian_channel_low)) return True def set_position(self, pos): self.state["position"] = pos self.state["last_price"] = self.quote["last_price"] self.target_pos.set_target_volume(self.state["position"]) def try_open(self): """开仓策略""" while self.state["position"] == 0: self.api.wait_update() if self.api.is_changing(self.klines.iloc[-1], "datetime"): # 如果产生新k线,则重新计算唐奇安通道及买卖单位 self.recalc_paramter() if self.api.is_changing(self.quote, "last_price"): print("最新价: %f" % self.quote.last_price) if self.quote.last_price > self.donchian_channel_high: # 当前价>唐奇安通道上轨,买入1个Unit;(持多仓) print("当前价>唐奇安通道上轨,买入1个Unit(持多仓): %d 手" % self.unit) self.set_position(self.state["position"] + self.unit) elif self.quote.last_price < self.donchian_channel_low: # 当前价<唐奇安通道下轨,卖出1个Unit;(持空仓) print("当前价<唐奇安通道下轨,卖出1个Unit(持空仓): %d 手" % self.unit) self.set_position(self.state["position"] - self.unit) def try_close(self): """交易策略""" while self.state["position"] != 0: self.api.wait_update() if self.api.is_changing(self.quote, "last_price"): print("最新价: ", self.quote.last_price) if self.state["position"] > 0: # 持多单 # 加仓策略: 如果是多仓且行情最新价在上一次建仓(或者加仓)的基础上又上涨了0.5N,就再加一个Unit的多仓,并且风险度在设定范围内(以防爆仓) if self.quote.last_price >= self.state[ "last_price"] + 0.5 * self.n and self.account.risk_ratio <= self.max_risk_ratio: print("加仓:加1个Unit的多仓") self.set_position(self.state["position"] + self.unit) # 止损策略: 如果是多仓且行情最新价在上一次建仓(或者加仓)的基础上又下跌了2N,就卖出全部头寸止损 elif self.quote.last_price <= self.state[ "last_price"] - 2 * self.n: print("止损:卖出全部头寸") self.set_position(0) # 止盈策略: 如果是多仓且行情最新价跌破了10日唐奇安通道的下轨,就清空所有头寸结束策略,离场 if self.quote.last_price <= min( self.klines. low[-self.donchian_channel_stop_profit - 1:-1]): print("止盈:清空所有头寸结束策略,离场") self.set_position(0) elif self.state["position"] < 0: # 持空单 # 加仓策略: 如果是空仓且行情最新价在上一次建仓(或者加仓)的基础上又下跌了0.5N,就再加一个Unit的空仓,并且风险度在设定范围内(以防爆仓) if self.quote.last_price <= self.state[ "last_price"] - 0.5 * self.n and self.account.risk_ratio <= self.max_risk_ratio: print("加仓:加1个Unit的空仓") self.set_position(self.state["position"] - self.unit) # 止损策略: 如果是空仓且行情最新价在上一次建仓(或者加仓)的基础上又上涨了2N,就平仓止损 elif self.quote.last_price >= self.state[ "last_price"] + 2 * self.n: print("止损:卖出全部头寸") self.set_position(0) # 止盈策略: 如果是空仓且行情最新价升破了10日唐奇安通道的上轨,就清空所有头寸结束策略,离场 if self.quote.last_price >= max( self.klines. high[-self.donchian_channel_stop_profit - 1:-1]): print("止盈:清空所有头寸结束策略,离场") self.set_position(0) def strategy(self): """海龟策略""" print("等待K线及账户数据...") deadline = time.time() + 5 while not self.recalc_paramter(): if not self.api.wait_update(deadline=deadline): raise Exception("获取数据失败,请确认行情连接正常并已经登录交易账户") while True: self.try_open() self.try_close()
#!usr/bin/env python3 #-*- coding:utf-8 -*- from tqsdk import TqApi, tafunc from tqsdk.ta import * api = TqApi() underlying_quote = api.get_quote("CFFEX.IF2002") klines = api.get_kline_serial('CFFEX.IF2002', 24 * 60 * 60, 20) v = tafunc.get_his_volatility(klines, underlying_quote) print("历史波动率:", v) quote = api.get_quote("CFFEX.IO2002-C-3550") bs_serise = BS_VALUE(klines, quote, 0.025) print("理论价:", list(round(bs_serise['bs_price'], 2))) klines2 = api.get_kline_serial(["CFFEX.IO2002-C-3550", "CFFEX.IF2002"], 24 * 60 * 60, 20) values = OPTION_VALUE(klines2, quote) print("内在价值:", list(values["intrins"])) print("时间价值:", list(values["time"])) impv = OPTION_IMPV(klines2, quote, 0.025) print("隐含波动率:", list(round(impv['impv'] * 100, 2))) greeks = OPTION_GREEKS(klines2, quote, 0.025, impv['impv']) print("delta:", list(greeks["delta"])) print("theta:", list(greeks["theta"])) print("gamma:", list(greeks["gamma"]))
__author__ = "Ringo" ''' 价格动量 策略 (难度:初级) 参考: https://www.shinnytech.com/blog/momentum-strategy/ 注: 该示例策略仅用于功能示范, 实盘时请根据自己的策略/经验进行修改 ''' from tqsdk import TqAccount, TqApi, TargetPosTask # 设置指定合约,获取N条K线计算价格动量 SYMBOL = "SHFE.au1912" N = 15 api = TqApi() klines = api.get_kline_serial(SYMBOL, 60*60*24, N) quote = api.get_quote(SYMBOL) target_pos = TargetPosTask(api, SYMBOL) position = api.get_position(SYMBOL) # 编写价格动量函数AR,以前N-1日K线计算价格动量ar def AR(kline1): spread_ho = sum(kline1.high[:-1] - kline1.open[:-1]) spread_oc = sum(kline1.open[:-1] - kline1.low[:-1]) # spread_oc 为0时,设置为最小价格跳动值 if spread_oc == 0: spread_oc = quote.price_tick ar = (spread_ho/spread_oc)*100 return ar
ls_symbols = ['SHFE.rb1910', 'SHFE.hc1910', 'CZCE.MA909', 'CZCE.TA909', 'DCE.i1909'] # ls_symbols = ['SHFE.fu1909', 'SHFE.bu1912', 'DCE.jd1909'] api = TqApi('SIM') # api = TqApi(TqSim(), backtest=TqBacktest(start_dt=dt.date(2019,1,2), end_dt=dt.date(2019,1,10))) dict_quotes = {} dict_klines = {} dict_positions = {} dict_target_pos = {} dict_update_kline_chan = {} dict_update_quote_chan = {} for SYMBOL in ls_symbols: dict_quotes[SYMBOL] = api.get_quote(SYMBOL) # 行情数据 dict_klines[SYMBOL] = api.get_kline_serial(SYMBOL, duration_seconds=15 * 60) dict_positions[SYMBOL] = api.get_position(SYMBOL) dict_target_pos[SYMBOL] = TargetPosTask(api, SYMBOL) dict_update_kline_chan[SYMBOL] = api.register_update_notify(dict_klines[SYMBOL]) dict_update_quote_chan[SYMBOL] = api.register_update_notify(dict_quotes[SYMBOL]) async def signal_generator(SYMBOL, strategy): """该task应用策略在价格触发时开仓,出发平仓条件时平仓""" klines = dict_klines[SYMBOL] position = dict_positions[SYMBOL] target_pos = dict_target_pos[SYMBOL] update_kline_chan = dict_update_kline_chan[SYMBOL] while True: target_pos_value = 0
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'limin' from tqsdk import TqApi ''' 画图示例: 在附图中画K线 注意:1 画图功能仅在天勤终端/天勤Vscode插件中生效,请在这两个平台中运行画图相关的代码 2 画图示例中用到的数据不含有实际意义,请根据自己的实际策略情况进行修改 ''' api = TqApi() klines = api.get_kline_serial("SHFE.cu1910", 86400) klines2 = api.get_kline_serial("SHFE.cu1911", 86400) # 在附图画出 cu1911 的K线: 需要将open、high、log、close的数据都设置正确 klines["cu1911.open"] = klines2["open"] klines["cu1911.high"] = klines2["high"] klines["cu1911.low"] = klines2["low"] klines["cu1911.close"] = klines2["close"] klines["cu1911.board"] = "B2" api.close() # 需要调用此函数将画图数据发送给天勤并关闭api
return up, up_limit, up_limit2, down, down_limit, down_limit2 acc = TqSim(init_balance=1000000) # 在创建 api 实例时传入 TqBacktest 就会进入回测模式 api = TqApi(acc, backtest=TqBacktest(start_dt=date(2018, 2, 1), end_dt=date(2018, 5, 1)), web_gui='http://127.0.0.1:8889') # kind1 = 'SHFE.cu1901' kind2 = 'SHFE.cu1902' # 获得 m1901 5分钟K线的引用 klines1 = api.get_kline_serial([kind1], 1 * 30, data_length=8000) klines2 = api.get_kline_serial([kind2], 1 * 30, data_length=8000) quote1 = api.get_quote(kind1) quote2 = api.get_quote(kind2) # # 创建 m1901 的目标持仓 task,该 task 负责调整 m1901 的仓位到指定的目标仓位 target_pos1 = TargetPosTask(api, kind1) target_pos2 = TargetPosTask(api, kind2) now1 = datetime.datetime.strptime(quote1.datetime, "%Y-%m-%d %H:%M:%S.%f") # 当前quote的时间 now2 = datetime.datetime.strptime(quote2.datetime, "%Y-%m-%d %H:%M:%S.%f") # 当前quote的时间 # api.wait_update() # time1 = time.ctime(klines2.iloc[-1].datetime/(10**9)) while True:
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'limin' from tqsdk import TqApi, TqAuth ''' 画图示例: 在主图中画线和方框 注意: 画图示例中用到的数据不含有实际意义,请根据自己的实际策略情况进行修改 ''' api = TqApi(web_gui=True, auth=TqAuth("信易账户", "账户密码")) # web_gui=True, 开启使用 web 界面查看绘图结果的功能 klines = api.get_kline_serial("SHFE.rb2105", 60) # 由于需要在浏览器中查看绘图结果,因此程序不能退出 while True: api.wait_update() # 当有业务信息发生变化时执行 # 当最后 1 根柱子最大最小值价差大于 0.05 时,在主图绘制信号 high = klines.iloc[-1].high low = klines.iloc[-1].low if high - low > 0.05: # 绘制直线, 每一个 id 对应同一条直线 api.draw_line(klines, -1, high, -1, low, id="box%.0f" % (klines.iloc[-1].id), color=0xaa662244, width=4) # 绘制字符串
''' import logging from tqsdk import TqApi, TqSim, TargetPosTask SYMBOL = "DCE.jd1905" # 合约代码 NDAY = 5 # 天数 K1 = 0.2 # 上轨K值 K2 = 0.2 # 下轨K值 api = TqApi(TqSim()) logger = logging.getLogger("TQ") logger.info("策略开始运行") quote = api.get_quote(SYMBOL) klines = api.get_kline_serial(SYMBOL, 24 * 60 * 60) # 86400使用日线 target_pos = TargetPosTask(api, SYMBOL) def dual_thrust(quote, klines): current_open = klines[-1]["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 # 下轨 logger.info("当前开盘价: %f, 上轨: %f, 下轨: %f" % (current_open, buy_line, sell_line)) return buy_line, sell_line
''' 连续3根阴线就做空,连续3根阳线就做多,否则空仓 ''' from tqsdk import TqApi, TargetPosTask api = TqApi() # 设定连续多少根阳线/阴线 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手") # 设置目标持仓为正数表示多头,负数表示空头,0表示空仓 target_pos.set_target_volume(1) elif all(down): print("连续阴线: 目标持仓 空头1手") target_pos.set_target_volume(-1)
''' 菲阿里四价 策略(日内突破策略, 在每日收盘前对所持合约进行平仓) 参考: https://www.shinnytech.com/blog/fairy-four-price/ 注: 该示例策略仅用于功能示范, 实盘时请根据自己的策略/经验进行修改 ''' from tqsdk import TqApi, TargetPosTask from datetime import datetime import time symbol = "SHFE.cu2002" # 合约代码 close_hour, close_minute = 14, 50 # 平仓时间 api = TqApi() # 使用模拟帐号直连行情和交易服务器 quote = api.get_quote(symbol) # 获取指定合约的盘口行情 klines = api.get_kline_serial(symbol, 24 * 60 * 60) # 获取日线 position = api.get_position(symbol) # 持仓信息 target_pos = TargetPosTask(api, symbol) # 目标持仓 top_rail = klines.high.iloc[-2] # 上轨: 昨日高点 bottom_rail = klines.low.iloc[-2] # 下轨: 昨日低点 print("上轨:", top_rail, ",下轨:", bottom_rail, ",昨日收盘价:", klines.close.iloc[-2], ",今日开盘价:", klines.open.iloc[-1]) while True: api.wait_update() if api.is_changing(klines.iloc[-1], "datetime"): # 如果产生一根新日线 (即到达下一个交易日): 重新获取上下轨 top_rail = klines.high.iloc[-2] bottom_rail = klines.low.iloc[-2] print("上轨:", top_rail, ",下轨:", bottom_rail, ",昨日收盘价:", klines.close.iloc[-2], ",今日开盘价:", klines.open.iloc[-1]) if api.is_changing(quote, "last_price"): # 如果行情最新价发生变化
class CuatroStrategy(Process): '''''' author = 'XIAO LI' boll_window = 20 boll_dev = 1.8 rsi_window = 14 rsi_signal = 20 fast_window = 4 slow_window = 26 trailing_long = 0.5 trailing_short = 0.3 vol = 1 boll_up = float('nan') boll_down = float('nan') rsi_value = float('nan') rsi_long = float('nan') rsi_short = float('nan') fast_ma = float('nan') slow_ma = float('nan') ma_trend = float('nan') intra_trade_high = float('nan') intra_trade_low = float('nan') long_stop = float('nan') short_stop = float('nan') parameters = [ 'boll_window' 'boll_dev' 'rsi_window' 'rsi_signal' 'fast_window' 'slow_window' 'trailing_long' 'trailing_short' 'vol' ] variables = [ 'boll_up' 'boll_down' 'rsi_value' 'rsi_long' 'rsi_short' 'fast_ma' 'slow_ma' 'ma_trend' 'intra_trade_high' 'intra_trade_low ' 'long_stop' 'short_stop' ] def __init__(self, symbol): Process.__init__(self) self.symbol = symbol self.rsi_long = 50 + self.rsi_signal self.rsi_short = 50 - self.rsi_signal self.api = TqApi(TqSim(init_balance=50000)) self.now = datetime.now() self.target_pos = TargetPosTask(self.api, self.symbol) self.ticks = self.api.get_tick_serial(self.symbol) self.klines5 = self.api.get_kline_serial(self.symbol, 60 * 5) self.klines15 = self.api.get_kline_serial(self.symbol, 60 * 15) self.position = self.api.get_position(self.symbol) def on_init(self): print(self.now, '策略初始化') def on_start(self): print(self.now, '策略启动') def on_stop(self): print(self.now, '策略停止') def on_tick(self, ticks): if self.api.is_changing(ticks, 'datetime'): if self.position.pos_long == 0 and self.position.pos_short == 0: if self.ma_trend > 0 and self.rsi_value >= self.rsi_long and ticks.iloc[-1].last_price > self.boll_up: self.target_pos.set_target_volume(self.vol) self.intra_trade_high = ticks.iloc[-1].last_price if self.ma_trend < 0 and self.rsi_value <= self.rsi_short and ticks.iloc[ -1].last_price < self.boll_down: self.target_pos.set_target_volume(-self.vol) self.intra_trade_low = ticks.iloc[-1].last_price elif self.position.pos_long > 0: self.intra_trade_high = max(self.intra_trade_high, ticks.iloc[-1].last_price) self.long_stop = (self.intra_trade_high - self.trailing_long * (self.boll_up - self.boll_down)) if ticks.iloc[-1].last_price < self.long_stop: self.target_pos.set_target_volume(0) self.intra_trade_high = float('nan') else: self.intra_trade_low = min(self.intra_trade_low, ticks.iloc[-1].last_price) self.short_stop = (self.intra_trade_low + self.trailing_short * (self.boll_up - self.boll_down)) if ticks.iloc[-1].last_price > self.short_stop: self.target_pos.set_target_volume(0) self.intra_trade_low = float('nan') def on_5minbar(self, klines5): if self.api.is_changing(klines5, 'datetime'): boll = ta.BOLL(klines5.iloc[:-1], self.boll_window, self.boll_dev).iloc[-1] self.boll_up = boll['top'] self.boll_down = boll['bottom'] self.rsi_value = ta.RSI(klines5.iloc[:-1], self.rsi_window).iloc[-1]['rsi'] def on_15minbar(self, klines15): if self.api.is_changing(klines15, 'datetime'): self.fast_ma = ta.SMA(klines15.iloc[:-1], self.fast_window, 2) self.slow_ma = ta.SMA(klines15.iloc[:-1], self.slow_window, 2) if self.fast_ma > self.slow_ma: self.ma_trend = 1 elif self.fast_ma < self.slow_ma: self.ma_trend = -1 else: self.ma_trend = 0 def on_order(self): if self.api.is_changing(self.api.get_order()): pass def on_trade(self): if self.api.is_changing(self.api.get_trade()): pass def run(self): self.on_init() self.on_start() while True: self.api.wait_update() self.on_tick(self.ticks) self.on_5minbar(self.klines5) self.on_15minbar(self.klines15) self.on_order() self.on_trade() self.on_stop()