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()
#!/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 ''' 如果当前价格大于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 -*- __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])
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手") target_pos.set_target_volume(3) # 交易 elif quote["last_price"] < sell_line: # 低于下轨
#!/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"] +
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()
def vwap_table(api: TqApi, symbol: str, target_pos: int, duration: float, account: Optional[Union[TqAccount, TqKq, TqSim]] = None): """ 返回基于 vwap 策略的计划任务时间表。下单需要配合 TargetPosScheduler 使用。 调用 vwap_table 函数,根据以下逻辑生成 time_table: 1. 根据 target_pos - 当前合约的净持仓,得到总的需要调整手数 2. 请求 symbol 合约的 ``1min`` K 线 3. 采样取用最近 10 日内,以合约当前行情时间的下一分钟为起点,每日 duration / 60 根 K 线, \ 例如当前合约时间为 14:35:35,那么采样是会使用 14:36:00 开始的分钟线 K 线 4. 按日期分组,分别计算交易日内,每根 K 线成交量占总成交量的比例 5. 计算最近 10 日内相同分钟内的成交量占比的算术平均数,将第 1 步得到的总调整手数按照得到的比例分配 6. 每一分钟,前 58s 以追加价格下单,后 2s 以对价价格下单 Args: api (TqApi): TqApi实例,该task依托于指定api下单/撤单 symbol (str): 拟下单的合约 symbol, 格式为 交易所代码.合约代码, 例如 "SHFE.cu2201" target_pos (int): 目标持仓手数 duration (int): 算法执行的时长,以秒为单位,必须是 60 的整数倍,时长可以跨非交易时间段,但是不可以跨交易日 * 设置为 60*10, 可以是 10:10~10:15 + 10:30~10:35 account (TqAccount/TqKq/TqSim): [可选]指定发送下单指令的账户实例, 多账户模式下,该参数必须指定 Returns: pandas.DataFrame: 本函数返回一个 pandas.DataFrame 实例. 表示一份计划任务时间表。每一行表示一项目标持仓任务,包含以下列: + interval: 当前这项任务的持续时间长度,单位为秒 + target_pos: 当前这项任务的目标持仓 + price: 当前这项任务的下单价格模式,支持 PASSIVE(排队价),ACTIVE(对价),None(不下单,表示暂停一段时间) Example1:: from tqsdk import TqApi, TargetPosScheduler from tqsdk.algorithm import vwap_table api = TqApi(auth="信易账户,用户密码") quote = api.get_quote("CZCE.MA109") # 设置 vwap 任务参数 time_table = vwap_table(api, "CZCE.MA109", -100, 600) # 目标持仓 -100 手,600s 内完成 print(time_table.to_string()) target_pos_sch = TargetPosScheduler(api, "CZCE.MA109", time_table) # 启动循环 while not target_pos_sch.is_finished(): api.wait_update() api.close() """ account = api._account._check_valid(account) if account is None: raise Exception(f"多账户模式下, 需要指定账户实例 account") TIME_CELL = 60 # 等时长下单的时间单元, 单位: 秒 HISTORY_DAY_LENGTH = 10 # 使用多少天的历史数据用来计算每个时间单元的下单手数 if duration % TIME_CELL or duration < 60: raise Exception(f"duration {duration} 参数应该为 {TIME_CELL} 的整数倍") pos = account.get_position(symbol) target_pos = int(target_pos) delta_pos = target_pos - pos.pos target_volume = abs(delta_pos) # 总的下单手数 if target_volume == 0: return DataFrame(columns=['interval', 'target_pos', 'price']) # 获取 Kline klines = api.get_kline_serial(symbol, TIME_CELL, data_length=int(10 * 60 * 60 / TIME_CELL * HISTORY_DAY_LENGTH)) klines["time"] = klines.datetime.apply( lambda x: datetime.fromtimestamp(x // 1000000000).time()) # k线时间 klines["date"] = klines.datetime.apply(lambda x: datetime.fromtimestamp( _get_trading_day_from_timestamp(x) // 1000000000).date()) # k线交易日 quote = api.get_quote(symbol) # 当前交易日完整的交易时间段 trading_timestamp = _get_trading_timestamp(quote, quote.datetime) trading_timestamp_nano_range = trading_timestamp[ 'night'] + trading_timestamp['day'] # 当前交易日完整的交易时间段 # 当前时间 行情时间 current_timestamp_nano = _get_trade_timestamp(quote.datetime, float('nan')) if not trading_timestamp_nano_range[0][ 0] <= current_timestamp_nano < trading_timestamp_nano_range[-1][1]: raise Exception("当前时间不在指定的交易时间段内") current_datetime = datetime.fromtimestamp(current_timestamp_nano // 1000000000) # 下一分钟的开始时间 next_datetime = current_datetime.replace(second=0) + timedelta(minutes=1) start_datetime_nano = int(next_datetime.timestamp()) * 1000000000 r = _rangeset_head( _rangeset_slice(trading_timestamp_nano_range, start_datetime_nano), int(duration * 1e9)) if not (r and trading_timestamp_nano_range[0][0] <= r[-1][-1] < trading_timestamp_nano_range[-1][1]): raise Exception("指定时间段超出当前交易日") start_datetime = datetime.fromtimestamp(start_datetime_nano // 1000000000) end_datetime = datetime.fromtimestamp((r[-1][-1] - 1) // 1000000000) time_slot_start = time(start_datetime.hour, start_datetime.minute) # 计划交易时段起始时间点 time_slot_end = time(end_datetime.hour, end_datetime.minute) # 计划交易时段终点时间点 if time_slot_end > time_slot_start: # 判断是否类似 23:00:00 开始, 01:00:00 结束这样跨天的情况 klines = klines[(klines["time"] >= time_slot_start) & (klines["time"] <= time_slot_end)] else: klines = klines[(klines["time"] >= time_slot_start) | (klines["time"] <= time_slot_end)] # 获取在预设交易时间段内的所有K线, 即时间位于 time_slot_start 到 time_slot_end 之间的数据 need_date = klines['date'].drop_duplicates()[-HISTORY_DAY_LENGTH:] klines = klines[klines['date'].isin(need_date)] grouped_datetime = klines.groupby(['date', 'time'])['volume'].sum() # 计算每个交易日内的预设交易时间段内的成交量总和(level=0: 表示按第一级索引"data"来分组)后,将每根k线的成交量除以所在交易日内的总成交量,计算其所占比例 volume_percent = grouped_datetime / grouped_datetime.groupby(level=0).sum() predicted_percent = volume_percent.groupby( level=1).mean() # 将历史上相同时间单元的成交量占比使用算数平均计算出预测值 # 计算每个时间单元的成交量预测值 time_table = DataFrame(columns=['interval', 'volume', 'price']) volume_left = target_volume # 剩余手数 percent_left = 1 # 剩余百分比 for index, value in predicted_percent.items(): volume = round(target_volume * (value / percent_left)) volume_left -= volume percent_left -= value append_time_table = pd.DataFrame([{ "interval": TIME_CELL - 2, "volume": volume, "price": "PASSIVE" }, { "interval": 2, "volume": 0, "price": "ACTIVE" }]) time_table = pd.concat([time_table, append_time_table], ignore_index=True) time_table['volume'] = time_table['volume'].mul(np.sign(delta_pos)) time_table['target_pos'] = time_table['volume'].cumsum() time_table['target_pos'] = time_table['target_pos'].add(pos.pos) time_table.drop(columns=['volume'], inplace=True) time_table = time_table.astype({ 'target_pos': 'int64', 'interval': 'float64' }) return time_table