Esempio n. 1
0
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)
Esempio n. 2
0
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()
Esempio n. 3
0
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()
Esempio n. 4
0
#!/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("目标持仓: 空仓")
Esempio n. 5
0
#!/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"])
Esempio n. 6
0
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手")
            target_pos.set_target_volume(3)  # 交易
Esempio n. 7
0
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