def download(return_paths=False): api = TqApi(TqSim()) download_tasks = {} csv_paths = [] for item in download_list: save_path = item.get("save_path", default_settings["save_path"]) symbol = item["symbol"] start_dt = item.get("start_dt", default_settings["start_dt"]) end_dt = item.get("end_dt", default_settings["end_dt"]) interval = item.get("interval", default_settings["interval"]) csv_file_name = symbol + "_" + interval + "_" + \ start_dt.strftime("%Y%m%d") + "_" + end_dt.strftime("%Y%m%d") + ".csv" csv_file_path = path.join(save_path, csv_file_name) if return_paths: csv_paths.append(csv_file_path) download_tasks[item["symbol"]] = DataDownloader( api, symbol_list=symbol, dur_sec=item.get("cycle", default_settings["cycle"]), start_dt=start_dt, end_dt=end_dt, csv_file_name=csv_file_path ) 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()}) if return_paths: return csv_paths
def get_tqsdk_data_kline(): api = TqApi(TqSim()) download_tasks = {} download_tasks["yzyl0905_min"] = DataDownloader( api, symbol_list=[ "DCE.m1905", "DCE.y1905", "DCE.p1905", "CZCE.RM905", "CZCE.OI905", ], dur_sec=60, start_dt=datetime(2019, 2, 1, 0, 0, 0), end_dt=datetime(2019, 4, 28, 0, 0, 0), csv_file_name="cu_min.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() })
def download_bar(self, symbol: str, exchange: Exchange, interval: Interval, start_dt: datetime, end_dt: datetime): csv_file_name = self.make_csvfile_name(symbol=symbol, exchange=exchange, interval=interval, start_dt=start_dt, end_dt=end_dt) if os.path.exists(csv_file_name): print(csv_file_name + "已存在,删除") os.remove(csv_file_name) # 下载从 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线数据会被跳过 with TqApi(TqSim()) as api: download_task = DataDownloader( api, symbol_list=[exchange.value + '.' + symbol], dur_sec=INTERVAL_2_SEC_MAP[interval], start_dt=start_dt, end_dt=end_dt, csv_file_name=csv_file_name) # 使用with closing机制确保下载完成后释放对应的资源 with closing(api): while not download_task.is_finished(): self.api.wait_update() print("tq download progress: ", "%.2f%%" % download_task.get_progress())
def test_tdsdk_quote(): api = TqApi(TqSim()) quote = api.get_quote("SHFE.cu1908") print(quote["last_price"], quote["volume"]) while True: api.wait_update() print(quote["datetime"], quote["last_price"])
def download_data(symbol_list: List[str], start_dt: datetime, end_dt: datetime, freq: str): """ :param symbol_list: a list of symbols :type symbol_list: List[str] :param start_dt: start date, default time of the day is 08:00 :type start_dt: str, datetime :param end_dt: end date, default time of the day is 08:00 :type end_dt: str, datetime :param freq: one of the data frequency, "tick", "s", "min", "5min", "h", "D" :type freq: str :param folderpath: folder path of the downloaded data :type folderpath: str :return: A dict of DataDownloader object with get_progress and is_Finished method. :rtype: Dict[str, DataDownloader] """ time_map = {"tick": 0, "s": 1, "min": 60, "5min": 5 * 60, "h": 3600, "D": 24 * 3600} if freq not in time_map: raise Exception("freq entered is not in the time_map.") _start_dt = start_dt _end_dt = end_dt if start_dt > end_dt: raise Exception("Start time has to be earlier than the end datetime.") api = TqApi(TqSim()) download_tasks = {} # create root folder for symbol in symbol_list: if symbol.split("@")[0] == 'KQ.m': root_sym = symbol.split("@")[1] subfolder = os.path.join(Default_Folder, "KQ") task_name = "{0}_{1}".format(root_sym, freq) else: root_sym = symbol[:-4] subfolder = os.path.join(Default_Folder, root_sym) task_name = "{0}_{1}".format(symbol, freq) if not os.path.exists(subfolder): os.mkdir(subfolder) filepath = os.path.join(subfolder, task_name + ".csv") print(filepath) if task_name not in download_tasks: try: # create download task download_tasks[task_name] = DataDownloader(api, symbol, time_map[freq], _start_dt, _end_dt, filepath) except Exception as inst: print(inst) 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()}) print("tasks finished.") return download_tasks
def __init__(self, event_engine: EventEngine): super().__init__(event_engine, "TQ") self._tqapi = api.TqApi(TqSim(), backtest=TqBacktest( start_dt=datetime.date(2019, 3, 20), end_dt=datetime.date(2019, 6, 20))) self._looper = Thread(target=self._run) self._bar_requests: List[SubscribeBarRequest] = [] self._bars_df: List[DataFrame] = []
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 download(task, instrument_code, duration, start_time, end_time, filename): api = TqApi(TqSim()) download_tasks = {} download_tasks[task] = DataDownloader(api, symbol_list=instrument_code, dur_sec=duration, start_dt=start_time, end_dt=end_time, csv_file_name=filename) # download_tasks["c1809"] = DataDownloader(api, symbol_list="DCE.c1809", dur_sec=24 * 60 * 60, # start_dt=date(2017, 9, 1), end_dt=date(2018, 9, 1), # csv_file_name="../DCE.c1809.csv") 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()})
def run(instrumentid, period, exchangeid='SHFE'): api = TqApi(TqSim()) inst = instrumentid instinfo = get_inst_info(inst) exchangeid=instinfo['ExchangeID'] period = int(period) if period is not None else 780 instid = ''.join([exchangeid, '.', inst]) datafile = inst + '_' + str(period) + '.csv' enddt = datetime.now() kd = DataDownloader(api, symbol_list=[instid], dur_sec=period, start_dt=datetime(2016, 1, 1), end_dt=enddt, csv_file_name=datafile) with closing(api): while not kd.is_finished(): api.wait_update() print(("progress: kline: %.2f%%" % kd.get_progress())) return datafile
def get_tqsdk_data(ex, symbol): bb = get_all_symbol_CFFEX() # # 下载从 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数据 name = ex + '.' + symbol ff_name = './data/' + ex + '_' + symbol + '.csv' print(symbol) print(name) print(ff_name) # //检查是否存在这个文件 bb = os.path.exists(ff_name) if bb == True: print('文件已经存在了!!') return api = TqApi(TqSim()) download_tasks = {} download_tasks["T_tick"] = DataDownloader(api, symbol_list=[name], dur_sec=0, start_dt=datetime(2000, 1, 1), end_dt=datetime(2019, 6, 1), csv_file_name=ff_name) # 使用with closing机制确保下载完成后释放对应的资源 with closing(api): while not all([v.is_finished() for v in download_tasks.values()]): api.wait_update() print( "progress: " + name, { k: ("%.2f%%" % v.get_progress()) for k, v in download_tasks.items() })
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 main(): api = TqApi(TqSim()) inst = instid.split('.')[1] tickfile = inst + 'tick.csv' stdt = datetime(2016, 1, 1) eddt = datetime.now() # eddt = datetime(2018, 8, 30) # 下载从 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线数据会被跳过 # 下载从 2018-05-01 到 2018-07-01 的 T1809 盘口Tick数据 td = DataDownloader(api, symbol_list=[instid], dur_sec=0, start_dt=stdt, end_dt=eddt, csv_file_name=tickfile) while not td.is_finished(): api.wait_update() print(("progress: tick:%.2f%%" % td.get_progress()))
max_positions = { "*****@*****.**": 1, "*****@*****.**": 4, } data_path = f"./logs/S05_{datetime.now().strftime('%Y%m%d%H%M%S')}" Path(data_path).mkdir(parents=True, exist_ok=False) file_log = os.path.join(data_path, "backtest.log") file_signals = os.path.join(data_path, "signals.txt") logger = create_logger(log_file=file_log, cmd=True, name="S") logger.info(f"标的配置:{max_positions}") logger.info(f"前端地址:http://127.0.0.1:{port}") logger.info(f"策略描述:{TradeAnalyze.__doc__}") account = TqSim(init_balance=init_balance) backtest = TqBacktest(start_dt=start_dt, end_dt=end_dt) api = TqApi(account=account, backtest=backtest, web_gui=f":{port}") symbols = list(max_positions.keys()) freqs = list(freqs_k_count.keys()) freq_seconds = { "1分钟": 60, "5分钟": 60 * 5, "15分钟": 60 * 15, "30分钟": 60 * 30, "60分钟": 60 * 60, "日线": 3600 * 24 } # 订阅K线
import os import numpy as np import pandas as pd import datetime as dt from contextlib import closing from tqsdk import TqApi, TqSim, TqBacktest, BacktestFinished, TargetPosTask from trading_strategies.technical_indicators import BB SYMBOL = 'SHFE.rb1905' CLOSE_HOUR, CLOSE_MINUTE = 14, 50 # 平仓时间 api = TqApi(TqSim(init_balance=100000), backtest=TqBacktest(start_dt=dt.date(2019, 1, 2), end_dt=dt.date(2019, 3, 6))) # api = TqApi('SIM') quote = api.get_quote(SYMBOL) klines_15 = api.get_kline_serial(SYMBOL, duration_seconds=15 * 60) klines_1 = api.get_kline_serial(SYMBOL, duration_seconds=60) position = api.get_position(SYMBOL) target_pos = TargetPosTask(api, SYMBOL) target_pos_value = position["volume_long"] - position[ "volume_short"] # 净目标净持仓数 account = api.get_account() with closing(api): while True:
''' import pretty_errors import datetime from datetime import date from tqsdk import TargetPosTask, TqApi, TqBacktest, tafunc, TqSim from tqsdk.ta import MA, MACD # 设置合约 SYMBOL = "DCE.i2005" # 设置均线长短周期 MA_SLOW, MA_FAST, EMA2_long = 8, 34, 55 #下面是回测用api,实盘时候记得注释掉。 api = TqApi(TqSim(200000), backtest=TqBacktest(start_dt=date(2019, 7, 15), end_dt=date(2020, 1, 15)), web_gui="http://127.0.0.1:61122/") #接收行情设置持仓目标 klines = api.get_kline_serial(SYMBOL, 60 * 60) # 1小时K线 klines_long = api.get_kline_serial(SYMBOL, 60 * 60 * 24) # 日K线 quote = api.get_quote(SYMBOL) position = api.get_position(SYMBOL) target_pos = TargetPosTask(api, SYMBOL) #计算MACD macd = MACD(klines, 12, 26, 9) macd_long = MACD(klines_long, 12, 26, 9)
#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'chengzhi' from tqsdk import TqApi, TqSim # 可以指定debug选项将调试信息写入指定的文件中 api = TqApi(TqSim(), debug="debug.log") quote = api.get_quote("SHFE.cu1906") print(quote.datetime, quote.last_price, quote.ask_price1, quote.ask_price2) while True: # 调用 wait_update 等待业务信息发生变化,例如: 行情发生变化, 委托单状态变化, 发生成交等等 # 注意:其他合约的行情的更新也会触发业务信息变化,因此下面使用 is_changing 判断 cu1906 的行情是否有变化 api.wait_update() # 如果 cu1906 的任何字段有变化,is_changing就会返回 True if api.is_changing(quote): print("行情变化", quote) # 只有当 cu1906 的最新价有变化,is_changing才会返回 True if api.is_changing(quote, "last_price"): print("最新价变化", quote.last_price) # 当 cu1906 的买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)
args = parser.parse_args() if args.SYMBOL != None: SYMBOL = args.SYMBOL else: SYMBOL = "DCE.i2005" # fake contract if args.YEAR != None: YEAR = int(args.YEAR) else: YEAR = 2020 #TODO:取当年值 #parse and decide time duration for backtesting #有些主力合约不分年份,分析月份后2015年开始逐年回测 if SYMBOL.endswith('01'): api = TqApi(TqSim(), backtest=TqBacktest(start_dt=date(YEAR-1, 7, 20), end_dt=date(YEAR-1, 12, 15))) elif SYMBOL.endswith('05'): api = TqApi(TqSim(), backtest=TqBacktest(start_dt=date(YEAR-1, 11, 20), end_dt=date(YEAR, 4, 15))) elif SYMBOL.endswith('09'): api = TqApi(TqSim(), backtest=TqBacktest(start_dt=date(YEAR, 3, 20), end_dt=date(YEAR, 8, 15))) else: logger.info("Not supported contract: %s"%SYMBOL) exit(1) #STEP2:策略执行log logger.info("Starting fohuitou strategy for: %s, actually year: %s"%(SYMBOL, YEAR)) 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)
log_path = 'E://proj-futures/logs_debug/' log_name = log_path + runningDate + '-' + SYMBOL + '-' + c + '.log' logfile = log_name fh = logging.FileHandler(logfile, mode='a+') 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(), backtest=TqBacktest(start_dt=date(YEAR, MONTH, DAY), end_dt=date(YEAR, MONTH, DAY))) logger.info("start zhendang_short_model_3 daily strategy for %s in %d.%d.%d!"%(SYMBOL, YEAR, MONTH, DAY)) #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) current_volume = 0 # 记录持仓量 cur_trading_date = '' traded_volume = 0
return False def get_param(klines1, klines2): diff = klines1['close'] - klines2['close'] up = np.percentile(diff, 85) up_limit = np.percentile(diff, 99) up_limit2 = np.percentile(diff, 60) down = np.percentile(diff, 15) down_limit = np.percentile(diff, 1) down_limit2 = np.percentile(diff, 40) 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)
long_call_threshold=long_call, #开仓方案一:买call、卖put、空期货的开仓临界值,可None long_put_threshold=short_call, #开仓方案一:买put、卖call、多期货的开仓临界值,可None return_threshold=return_threshold, #开仓方案二:按照理论收益率(=残差/保证金占用)来开仓,可None max_margin=max_margin, #最大保证金占用,可None ) global trade_dict # 使用future_symbol可以查询这组put-call parity arbitrage对象 trade_dict[future_product_id] = trade print("期货代码:" + kq_m.underlying_symbol) future_target_pos = TargetPosTask(api, kq_m.underlying_symbol) # 订阅所有的期权合约套利组 for opt in opts.values(): trade.parity_quote_task(opt, kq_m.underlying_symbol, future_target_pos) api = TqApi(TqSim(), web_gui=True) # api = TqApi(TqAccount("G光大期货", "[账号]", "[密码]"), web_gui=True) # api = TqApi(backtest=TqBacktest(start_dt=datetime(2020, 2, 3, 9), end_dt=datetime(2020, 2, 14, 16))) subscribe_main_parity(api, "CZCE.SR", "SR", "SR", -100, -100, None, None) subscribe_main_parity(api, "CZCE.CF", "CF", "CF", -100, -100, 12400, 13800) subscribe_main_parity(api, "CZCE.MA", "MA", "MA", -100, -100, 1950, 2175) subscribe_main_parity(api, "CZCE.TA", "TA", "TA", -100, -100, 4300, 4650) subscribe_main_parity(api, "DCE.c", "c", "c_o", -100, -100, 1820, 2000) subscribe_main_parity(api, "DCE.i", "i", "i_o", -100, -100, None, None) subscribe_main_parity(api, "DCE.m", "m", "m_o", -100, -100, 2500, 2850) # subscribe_main_parity(api, "CFFEX.IF", "i", "m_o", -100, -100, 2500, 2850) def save_all(trade_dict): """
''' 菲阿里四价(日内突破策略, 在每日收盘前对所持合约进行平仓) 注: demo仅用于示范如何使用TqSdk获取行情及编写策略程序 若需实际应用, 需要用户根据自己的交易经验进行修改 ''' from tqsdk import TqApi, TqSim, TargetPosTask from datetime import datetime import time symbol = "SHFE.cu1905" # 合约代码 close_hour, close_minute = 14, 50 # 平仓时间 api = TqApi(TqSim()) # 使用模拟帐号直连行情和交易服务器 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[-2]["high"] # 上轨: 昨日高点 bottom_rail = klines[-2]["low"] # 下轨: 昨日低点 print("上轨:", top_rail, ",下轨:", bottom_rail, ",昨日收盘价:", klines[-2]["close"], ",今日开盘价:", klines[-1]["open"]) while True: api.wait_update() if api.is_changing(klines[-1], "datetime"): # 如果产生一根新日线 (即到达下一个交易日): 重新获取上下轨 top_rail = klines[-2]["high"]
api.insert_order(symbol=品种, direction="BUY", offset="CLOSETODAY", volume=空仓2) else: api.insert_order(symbol=品种, direction="BUY", offset="CLOSE", volume=空仓2) def close_judge(): global 当前状态 if 当前状态 == "已开多仓等待平仓": if get_open("BP"): close_out(品种) if 当前状态 == "已开空仓等待平仓": if get_open("SP"): close_out(品种) api = api.TqApi(TqSim()) klines = api.get_kline_serial(品种, period) #kline_count() open_judge() close_judge() while True: api.wait_update() print()
from tqsdk import TqApi, TqSim, TqBacktest, BacktestFinished from tqsdk.ta import MA import time from datetime import date acc = TqSim() 品种 = "DCE.p2001" 一跳价格 = 2 一次下多少单子 = 1 当前状态 = '寻找开仓机会' 检测最近多少tick序列 = 10 波动开仓跳数 = 15 委托远离几条撤单 = 10 委托间隔多少秒撤单 = 120 保本损改变条件 = 20 止损 = 10 止盈 = 30 单跟1分钟超过多少平仓 = 20 止损临时 = 0 委托单子 = 0 委托时间 = 0 def 开仓判断(行情, tick序列): global 委托单子, 当前状态, 止损临时, 委托时间 if 当前状态 == '寻找开仓机会': mymax = max(tick序列['last_price']) mymin = min(tick序列['last_price']) if mymax - mymin > 波动开仓跳数 * 一跳价格: 当前状态 = '检测委托' 止损临时 = 止损
def TianqinBacktesing(start_date, end_date, symbol, duration_seconds, init_balance=200000): # TqBacktest api = TqApi(TqSim(init_balance=init_balance), backtest=TqBacktest(start_dt=start_date, end_dt=end_date)) # TqBacktest with Tianqin Terminal # api = TqApi('SIM', backtest=TqBacktest(start_dt=start_date, end_dt=end_date)) quote = api.get_quote(symbol) klines = api.get_kline_serial(symbol, duration_seconds=duration_seconds) # 日线 target_pos = TargetPosTask(api, symbol) with closing(api): try: while True: while not api.is_changing(klines[-1], "datetime"): # 等到达下一个交易日 api.wait_update() while True: api.wait_update() # 在收盘后预测下一交易日的涨跌情况 if api.is_changing(quote, "datetime"): now = dt.datetime.strptime( quote["datetime"], "%Y-%m-%d %H:%M:%S.%f") # 当前quote的时间 print(now) # 判断是否到达预定收盘时间: 如果到达 则认为本交易日收盘, 此时预测下一交易日的涨跌情况, 并调整为对应仓位 # if now.hour == close_hour and now.minute >= close_minute: # # 1- 获取数据 # x_train, y_train, x_predict = get_prediction_data(klines, 75) # 参数1: K线, 参数2:需要的数据长度 # # # 2- 利用机器学习算法预测下一个交易日的涨跌情况 # # n_estimators 参数: 选择森林里(决策)树的数目; bootstrap 参数: 选择建立决策树时,是否使用有放回抽样 # clf = RandomForestClassifier(n_estimators=30, bootstrap=True) # clf.fit(x_train, y_train) # 传入训练数据, 进行参数训练 # predictions.append(bool(clf.predict([x_predict]))) # 传入测试数据进行预测, 得到预测的结果 # # # 3- 进行交易 # if predictions[-1] == True: # 如果预测结果为涨: 买入 # print(quote["datetime"], "预测下一交易日为 涨") # target_pos.set_target_volume(10) # else: # 如果预测结果为跌: 卖出 # print(quote["datetime"], "预测下一交易日为 跌") # target_pos.set_target_volume(-10) # break except BacktestFinished: # 回测结束, 获取预测结果,统计正确率 # df_klines = klines.to_dataframe() # 将K线序列中的数据转换为 pandas.DataFrame # df_klines["pre_close"] = df_klines["close"].shift(1) # 增加 pre_close(上一交易日的收盘价) 字段 # df_klines = df_klines[-len(predictions) + 1:] # 取出在回测日期内的K线数据 # df_klines["prediction"] = predictions[:-1] # 增加预测的本交易日涨跌情况字段(向后移一个数据目的: 将 本交易日对应下一交易日的涨跌 调整为 本交易日对应本交易日的涨跌) # results = (df_klines["close"] - df_klines["pre_close"] >= 0) == df_klines["prediction"] # # print(df_klines) print("----回测结束----") # print("预测结果正误:\n", results) # print("预测结果数目统计: 总计", len(results), "个预测结果") # print(pd.value_counts(results)) # print("预测的准确率:") # print((pd.value_counts(results)[True]) / len(results)) return BacktestFinished
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() turtle = Turtle(TqSim(), "SHFE.au1812") print("策略开始运行") try: turtle.state = json.load(open("turtle_state.json", "r")) # 读取数据: 本策略目标净持仓数,上一次开仓价 except FileNotFoundError: pass print("当前持仓数: %d, 上次调仓价: %f" % (turtle.state["position"], turtle.state["last_price"])) try: turtle.strategy() finally: turtle.api.close() json.dump(turtle.state, open("turtle_state.json", "w")) # 保存数据
from QuantWorkshopTq.strategy.scalping import Scalping, strategy_parameter if __name__ == '__main__': # 自定义变量 backtest_capital: float = 100000.0 replay_date: date = date(2020, 9, 24) # 加载 .env 变量 load_dotenv(find_dotenv()) # 天勤账号 TQ_ACCOUNT: str = os.environ.get('TQ_ACCOUNT') TQ_PASSWORD: str = os.environ.get('TQ_PASSWORD') # 天勤API tq_api: TqApi = TqApi(TqSim(backtest_capital), backtest=TqReplay(replay_date), web_gui='http://127.0.0.1:8888', auth='%s,%s' % (TQ_ACCOUNT, TQ_PASSWORD)) # 策略参数 parameter: StrategyParameter = strategy_parameter parameter.set_parameters({ 'max_position': 30, # 最大持仓手数 'close_spread': 1, # 平仓价差 'order_range': 3, # 挂单范围 'closeout_long': 5, # 多单强平点差 'closeout_short': 5, # 空单强平点差 'volume_per_order': 2, # 每笔委托手数 'volume_per_price': 3 # 每价位手数 })
def backtest(): #获取命令行参数 parser = argparse.ArgumentParser() parser.add_argument('--source_file') parser.add_argument('--instance_id') parser.add_argument('--instance_file') parser.add_argument('--output_file') args = parser.parse_args() s = TqSim() report_file = open(args.output_file, "a+") logger = logging.getLogger("TQ") logger.setLevel(logging.INFO) logger.addHandler(TqBacktestLogger(s, report_file)) # 加载策略文件 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", []) start_date = datetime.date(instance["start_date"] // 10000, instance["start_date"] % 10000 // 100, instance["start_date"] % 100) end_date = datetime.date(instance["end_date"] // 10000, instance["end_date"] % 10000 // 100, instance["end_date"] % 100) 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 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: __import__(module_name) except ModuleNotFoundError: logger.exception("加载策略文件失败") return except IndentationError: logger.exception("策略文件缩进格式错误") return except Exception as e: pass param_list, start_date, end_date = input_param_backtest(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": "%04d/%02d/%02d-%04d/%02d/%02d, %s" % (start_date.year, start_date.month, start_date.day, end_date.year, end_date.month, end_date.day, json.dumps(param_list)), "start_date": start_date.year * 10000 + start_date.month * 100 + start_date.day, "end_date": end_date.year * 10000 + end_date.month * 100 + end_date.day, "param_list": param_list, }, param_file) # 开始回测 api = TqApi(s, backtest=TqBacktest(start_dt=start_date, end_dt=end_date)) sys.stdout = PrintWriter(report_file, args.instance_id) try: json.dump( { "aid": "desc", "desc": "%04d/%02d/%02d-%04d/%02d/%02d, %s" % (start_date.year, start_date.month, start_date.day, end_date.year, end_date.month, end_date.day, json.dumps(param_list)), "start_date": start_date.year * 10000 + start_date.month * 100 + start_date.day, "end_date": end_date.year * 10000 + end_date.month * 100 + end_date.day, "param_list": param_list, }, report_file) report_file.write("\n") api.create_task(account_watcher(api, s, report_file)) try: 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 tqsdk.exceptions.BacktestFinished: logger.info("策略回测结束") except Exception as e: logger.exception("策略执行中遇到异常", exc_info=True) finally: if not api.loop.is_closed(): api.close()
YEAR = 2020 #TODO:取当年值 if args.ZC1 != None: ZC1 = float(args.ZC1) else: ZC1 = 0.0 if args.ZC2 != None: ZC2 = float(args.ZC2) else: ZC2 = 0.0 #parse and decide time duration for backtesting #有些主力合约不分年份,分析月份后2015年开始逐年回测 if SYMBOL.endswith('01'): api = TqApi(TqSim(), backtest=TqBacktest(start_dt=date(YEAR - 1, 7, 20), end_dt=date(YEAR - 1, 12, 15))) elif SYMBOL.endswith('05'): api = TqApi(TqSim(), backtest=TqBacktest(start_dt=date(YEAR - 1, 11, 20), end_dt=date(YEAR, 4, 15))) elif SYMBOL.endswith('09'): api = TqApi(TqSim(), backtest=TqBacktest(start_dt=date(YEAR, 3, 20), end_dt=date(YEAR, 8, 15))) else: logger.info("Not supported contract: %s" % SYMBOL) exit(1) #STEP2:策略执行log
__author__ = 'limin' ''' Dual Thrust策略 参考: https://www.shinnytech.com/blog/dual-thrust ''' 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)
wma_data = talib.WMA(close_prices, timeperiod=30)[-n:] # WMA指标 mom_data = talib.MOM(close_prices, timeperiod=30)[-n:] # MOM指标 x_all = list(zip(sma_data, wma_data, mom_data)) # 样本特征组 y_all = list(klines[i]["close"] >= klines[i - 1]["close"] for i in list(reversed(range(-1, -n - 1, -1)))) # 样本标签组 # x_all: 大前天指标 前天指标 昨天指标 (今天指标) # y_all: (大前天) 前天 昨天 今天 -明天- # 准备算法需要用到的数据 x_train = x_all[: -1] # 训练数据: 特征 x_predict = x_all[-1] # 预测数据(用本交易日的指标预测下一交易日的涨跌) y_train = y_all[1:] # 训练数据: 标签 (去掉第一个数据后让其与指标隔一位对齐(例如: 昨天的特征 -> 对应预测今天的涨跌标签)) return x_train, y_train, x_predict predictions = [] # 用于记录每次的预测结果(在每个交易日收盘时用收盘数据预测下一交易日的涨跌,并记录在此列表里) api = TqApi(TqSim(), backtest=TqBacktest(start_dt=datetime.date(2018, 7, 2), end_dt=datetime.date(2018, 9, 26))) quote = api.get_quote(symbol) klines = api.get_kline_serial(symbol, duration_seconds=24 * 60 * 60) # 日线 target_pos = TargetPosTask(api, symbol) with closing(api): try: while True: while not api.is_changing(klines[-1], "datetime"): # 等到达下一个交易日 api.wait_update() while True: api.wait_update() # 在收盘后预测下一交易日的涨跌情况 if api.is_changing(quote, "datetime"): now = datetime.datetime.strptime(quote["datetime"], "%Y-%m-%d %H:%M:%S.%f") # 当前quote的时间 # 判断是否到达预定收盘时间: 如果到达 则认为本交易日收盘, 此时预测下一交易日的涨跌情况, 并调整为对应仓位 if now.hour == close_hour and now.minute >= close_minute: