0
点赞
收藏
分享

微信扫一扫

量化交易之vnpy篇 - 同步模块避开自成交风险、新增同步完成提示


"""
事情起因:融行虽然有规避自成交的功能模块;但还有很多情况,程序同时发相同合约多空两向的单子,融行并不会做处理,估计这是融行系统的一个bug。
但现在的MOM账户大都用的是融行系统,所以自成交风险的避免还是要我们自己程序这边来处理。
"""

from vnpy.app.position_manager import StrategyTemplate
from vnpy.trader.utility import BarGenerator

import math

from time import sleep

from vnpy.app.position_manager.tools.position_operator.position_operator import TQZPositionJsonOperator
from vnpy.app.position_manager.tools.symbol_operator.symbol_operator import (
TQZSymbolOperator,
TQZFuturesType
)

from vnpy.app.position_manager.tools.position_data.position_data import TQZPositionData

from vnpy.trader.object import (
TickData,
BarData
)

from vnpy.trader.constant import Direction


class PositionManager(StrategyTemplate):

author = "Post-Truth"

# 策略参数
offset_tick_counts = 10
parameters = ["offset_tick_counts"]
variables = []

def __init__(self, strategy_engine, strategy_name, vt_symbols, setting):
""" """
super().__init__(strategy_engine, strategy_name, vt_symbols, setting)
print("PositionManager init")

self.bar_generators: {str: BarGenerator} = {}
self.vt_symbols_limit_prices: {str: TickData} = {}

self.strategy_position_dictionary = self.tqz_get_current_cta_strategy_data()
print("cta_strategy_data: " + str(self.strategy_position_dictionary))

self.strategy_vt_symbols = TQZSymbolOperator.tqz_get_strategy_vt_symbols(self.strategy_position_dictionary.keys())

self.last_time_slot: {str, int} = {}
self.last_minute: {str, int} = {}
self.is_new: {str, bool} = {}
self.is_syn: {str, bool} = {}

for vt_symbol in self.vt_symbols:
self.bar_generators[vt_symbol] = BarGenerator(on_bar=self.on_bar)
self.last_time_slot[vt_symbol] = 0
self.last_minute[vt_symbol] = -1
self.is_syn[vt_symbol] = False

def on_init(self):
"""
Callback when strategy is inited.
"""

print("PositionManager on_init")
self.write_log("策略初始化")

def on_start(self):
"""
Callback when strategy is started.
"""

print("PositionManager on_start")
self.write_log("策略启动")

def on_stop(self):
"""
Callback when strategy is stopped.
"""
print("on_stop")
self.write_log("策略停止")

def on_tick(self, tick):
"""
Callback of new tick data update.
"""

""" bar type
self.vt_symbols_limit_prices[tick.vt_symbol] = tick
self.bar_generators[tick.vt_symbol].update_tick(tick)
"""

self.vt_symbols_limit_prices[tick.vt_symbol] = tick
self.on_x_seconds(tick=tick)

def on_x_seconds(self, tick: TickData, seconds_interval: int = 15):
"""
Callback when x seconds pass or new minute coming.
"""
if self.__is_new_time_slot(tick=tick, seconds_interval=seconds_interval) is False:
return

self.cancel_all()

print("tick.vt_symbol: " + str(tick.vt_symbol), end=" ")
print("datatime: " + str(tick.datetime))

# get current strategy data
self.strategy_position_dictionary = self.tqz_get_current_cta_strategy_data()

strategy_position_buy, strategy_position_sell, real_position_buy, real_position_sell = self.tqz_get_strategy_position_and_real_position(
market_vt_symbol=tick.vt_symbol,
strategy_data=self.strategy_position_dictionary
)
current_futures_type = TQZSymbolOperator.tqz_get_futures_type(vt_symbol=tick.vt_symbol)
min_offset_price = self.strategy_engine.contracts[tick.vt_symbol].pricetick

# do nothing when current symbol is in syncronized condition
is_syn = self.__tqz_strategy_is_real(
strategy_position_buy=strategy_position_buy,
strategy_position_sell=strategy_position_sell,
real_position_buy=real_position_buy,
real_position_sell=real_position_sell,
futures_type=current_futures_type
)
if is_syn is True:
self.is_syn[tick.vt_symbol] = is_syn

if False not in self.is_syn.values():
print("account is syn.")
return

if (tick.vt_symbol not in self.strategy_vt_symbols) or current_futures_type in [TQZFuturesType.COMMODITY_FUTURES, TQZFuturesType.TREASURY_FUTURES]:

self.tqz_synchronization_position_double_direction_mode(
market_vt_symbol=tick.vt_symbol,
now_price=tick.last_price,
offset_price=(min_offset_price * self.offset_tick_counts),
strategy_position_buy=strategy_position_buy,
strategy_position_sell=strategy_position_sell,
real_position_buy=real_position_buy,
real_position_sell=real_position_sell
)

elif current_futures_type is TQZFuturesType.STOCK_INDEX_FUTURES:

self.tqz_synchronization_position_cffex_lock_mode(
market_vt_symbol=tick.vt_symbol,
now_price=tick.last_price,
offset_price=(min_offset_price * self.offset_tick_counts),
strategy_position_net=(strategy_position_buy - strategy_position_sell),
real_position_net=(real_position_buy - real_position_sell)
)

else:
self.write_log("futures_type: " + str(current_futures_type) + " is out of futures type")

self.put_event()
sleep(0.1)


def __is_new_time_slot(self, tick: TickData, seconds_interval):
"""
Judge current time_slot is new or not.
"""

current_time_slot = math.floor(tick.datetime.second / seconds_interval)

if tick.datetime.minute != self.last_minute[tick.vt_symbol]: # new minute is come
self.last_time_slot[tick.vt_symbol], self.last_minute[tick.vt_symbol], self.is_new[tick.vt_symbol] = current_time_slot, tick.datetime.minute, True
elif current_time_slot != self.last_time_slot[tick.vt_symbol]: # new minute is not come, but last_time_slot is update
self.last_time_slot[tick.vt_symbol], self.last_minute[tick.vt_symbol], self.is_new[tick.vt_symbol] = current_time_slot, tick.datetime.minute, True
else:
self.is_new[tick.vt_symbol] = False

return self.is_new[tick.vt_symbol]


# --- old modern ---
def on_bar(self, bar: BarData):
"""
Callback of new bar data update.
"""
self.cancel_all()
print("bar.vt_symbol: " + str(bar.vt_symbol), end=" ")
print("datatime: " + str(bar.datetime))

# get current strategy data
self.strategy_position_dictionary = self.tqz_get_current_cta_strategy_data()

strategy_position_buy, strategy_position_sell, real_position_buy, real_position_sell = self.tqz_get_strategy_position_and_real_position(
market_vt_symbol=bar.vt_symbol,
strategy_data=self.strategy_position_dictionary
)
current_futures_type = TQZSymbolOperator.tqz_get_futures_type(vt_symbol=bar.vt_symbol)
min_offset_price = self.strategy_engine.contracts[bar.vt_symbol].pricetick

# do nothing when current symbol is in syncronized condition
if self.__tqz_strategy_is_real(strategy_position_buy=strategy_position_buy, strategy_position_sell=strategy_position_sell, real_position_buy=real_position_buy, real_position_sell=real_position_sell, futures_type=current_futures_type) is True:
return

if (bar.vt_symbol not in self.strategy_vt_symbols) or current_futures_type in [TQZFuturesType.COMMODITY_FUTURES, TQZFuturesType.TREASURY_FUTURES]:

self.tqz_synchronization_position_double_direction_mode(
market_vt_symbol=bar.vt_symbol,
now_price=bar.close_price,
offset_price=(min_offset_price * self.offset_tick_counts),
strategy_position_buy=strategy_position_buy,
strategy_position_sell=strategy_position_sell,
real_position_buy=real_position_buy,
real_position_sell=real_position_sell
)

elif current_futures_type is TQZFuturesType.STOCK_INDEX_FUTURES:

self.tqz_synchronization_position_cffex_lock_mode(
market_vt_symbol=bar.vt_symbol,
now_price=bar.close_price,
offset_price=(min_offset_price * self.offset_tick_counts),
strategy_position_net=(strategy_position_buy - strategy_position_sell),
real_position_net=(real_position_buy - real_position_sell)
)

else:
self.write_log("futures_type: " + str(current_futures_type) + " is out of futures type")

self.put_event()

sleep(0.2)


def tqz_synchronization_position_cffex_lock_mode(self, market_vt_symbol, now_price, offset_price, strategy_position_net, real_position_net):
"""
synchronization position with lock mode(cffex mode)
"""

vt_orderids = []
buy_price = min(now_price + offset_price, self.vt_symbols_limit_prices[market_vt_symbol].limit_up)
sell_price = max(now_price - offset_price, self.vt_symbols_limit_prices[market_vt_symbol].limit_down)


if strategy_position_net >= 0 and real_position_net >= 0:

if strategy_position_net > real_position_net:

lot = TQZPositionData.tqz_risk_control(lot=strategy_position_net-real_position_net)
print(f'开多 {str(lot)} 手', end=" ")
vt_orderids = self.buy(vt_symbol=market_vt_symbol, price=buy_price, volume=lot, lock=True)
print(f'vt_orderids: {vt_orderids}')

elif strategy_position_net < real_position_net:

lot = TQZPositionData.tqz_risk_control(lot=real_position_net - strategy_position_net)
print(f'平多 {str(lot)} 手', end=" ")
vt_orderids = self.sell(vt_symbol=market_vt_symbol, price=sell_price, volume=lot, lock=True)
print(f'vt_orderids: {vt_orderids}')

elif strategy_position_net is real_position_net:
print(f'净仓相等, 不做处理')

elif strategy_position_net >= 0 and real_position_net <= 0:

lot = TQZPositionData.tqz_risk_control(lot=strategy_position_net-real_position_net)
print(f'开多 {str(lot)} 手', end=" ")
vt_orderids = self.buy(vt_symbol=market_vt_symbol, price=buy_price, volume=lot, lock=True)
print(f'vt_orderids: {vt_orderids}')

elif strategy_position_net <= 0 and real_position_net >= 0:

lot = TQZPositionData.tqz_risk_control(lot=real_position_net - strategy_position_net)
print(f'开空 {str(lot)} 手', end=" ")
vt_orderids = self.short(vt_symbol=market_vt_symbol, price=sell_price, volume=lot, lock=True)
print(f'vt_orderids: {vt_orderids}')

elif strategy_position_net <= 0 and real_position_net <= 0:

if abs(strategy_position_net) > abs(real_position_net):

lot = TQZPositionData.tqz_risk_control(lot=abs(strategy_position_net)-abs(real_position_net))
print(f'开空 {str(lot)} 手', end=" ")
vt_orderids = self.short(vt_symbol=market_vt_symbol, price=sell_price, volume=lot, lock=True)
print(f'vt_orderids: {vt_orderids}')

elif abs(strategy_position_net) < abs(real_position_net):

lot = TQZPositionData.tqz_risk_control(lot=abs(real_position_net) - abs(strategy_position_net))
print(f'平空 {str(lot)} 手', end=" ")
vt_orderids = self.cover(vt_symbol=market_vt_symbol, price=buy_price, volume=lot, lock=True)
print(f'vt_orderids: {vt_orderids}')

elif strategy_position_net is real_position_net:
print(f'净仓相等, 不做处理')

return vt_orderids

def tqz_synchronization_position_double_direction_mode(self, market_vt_symbol, now_price, offset_price, strategy_position_buy, strategy_position_sell, real_position_buy, real_position_sell):

buy_vt_orderids = []
sell_vt_orderids = []
buy_price = min(now_price + offset_price, self.vt_symbols_limit_prices[market_vt_symbol].limit_up)
sell_price = max(now_price - offset_price, self.vt_symbols_limit_prices[market_vt_symbol].limit_down)

interval = " | "
print(market_vt_symbol, end=" ")
if strategy_position_buy > real_position_buy:

lot = TQZPositionData.tqz_risk_control(lot=strategy_position_buy - real_position_buy)
print(f'开多 {str(lot)} 手', end=" ")
buy_vt_orderids = self.buy(vt_symbol=market_vt_symbol, price=buy_price, volume=lot)
print(f'buy_result: {buy_vt_orderids}', end=interval)

return buy_vt_orderids

elif strategy_position_buy < real_position_buy:

lot = TQZPositionData.tqz_risk_control(lot=real_position_buy - strategy_position_buy)
print(f'平多 {str(lot)} 手', end=" ")
buy_vt_orderids = self.sell(vt_symbol=market_vt_symbol, price=sell_price, volume=lot)
print(f'sell_result: {buy_vt_orderids}', end=interval)

return buy_vt_orderids

elif strategy_position_buy is real_position_buy:
print("多单匹配 不处理", end=interval)

if strategy_position_sell > real_position_sell:

lot = TQZPositionData.tqz_risk_control(lot=strategy_position_sell - real_position_sell)
print(f'开空 {str(lot)} 手', end=" ")
sell_vt_orderids = self.short(vt_symbol=market_vt_symbol, price=sell_price, volume=lot)
print(f'short_result: {sell_vt_orderids}')

return sell_vt_orderids

elif strategy_position_sell < real_position_sell:

lot = TQZPositionData.tqz_risk_control(lot=real_position_sell - strategy_position_sell)
print(f'平空 {str(lot)} 手', end=" ")
sell_vt_orderids = self.cover(vt_symbol=market_vt_symbol, price=buy_price, volume=lot)
print(f'cover_result: {sell_vt_orderids}')

return sell_vt_orderids

elif strategy_position_sell is real_position_sell:
print("空单匹配 不处理")

return list(set(buy_vt_orderids + sell_vt_orderids))

def tqz_synchronization_position_min_netting_mode(self, market_vt_symbol, now_price, offset_price, strategy_position_buy, strategy_position_sell, real_position_buy, real_position_sell):
"""
synchronization position in min netting with double direction(buy direction & sell direction) mode.
"""

net_buy_abs = abs(strategy_position_buy - real_position_buy)
net_sell_abs = abs(strategy_position_sell - real_position_sell)
buy_vt_orderids = []
sell_vt_orderids = []

buy_price = min(now_price + offset_price, self.vt_symbols_limit_prices[market_vt_symbol].limit_up)
sell_price = max(now_price - offset_price, self.vt_symbols_limit_prices[market_vt_symbol].limit_down)

interval = " | "
print(market_vt_symbol, end=" ")
if net_buy_abs >= net_sell_abs:

if strategy_position_buy < real_position_buy:
lot = TQZPositionData.tqz_risk_control(lot=real_position_buy - strategy_position_buy)
print(f'平多 {str(lot)} 手', end=" ")
buy_vt_orderids = self.sell(vt_symbol=market_vt_symbol, price=sell_price, volume=lot)
print(f'sell_result: {buy_vt_orderids}', end=interval)

if strategy_position_sell > real_position_sell:
lot = TQZPositionData.tqz_risk_control(lot=strategy_position_sell - real_position_sell)
print(f'开空 {str(lot)} 手', end=" ")
sell_vt_orderids = self.short(vt_symbol=market_vt_symbol, price=sell_price, volume=lot)
print(f'short_result: {sell_vt_orderids}')

else:

if strategy_position_buy > real_position_buy:
lot = TQZPositionData.tqz_risk_control(lot=strategy_position_buy - real_position_buy)
print(f'开多 {str(lot)} 手', end=" ")
buy_vt_orderids = self.buy(vt_symbol=market_vt_symbol, price=buy_price, volume=lot)
print(f'buy_result: {buy_vt_orderids}', end=interval)

if strategy_position_sell < real_position_sell:
lot = TQZPositionData.tqz_risk_control(lot=real_position_sell - strategy_position_sell)
print(f'平空 {str(lot)} 手', end=" ")
sell_vt_orderids = self.cover(vt_symbol=market_vt_symbol, price=buy_price, volume=lot)
print(f'cover_result: {sell_vt_orderids}')

return list(set(buy_vt_orderids + sell_vt_orderids))

def tqz_synchronization_position_net_mode(self, market_vt_symbol, now_price, offset_price, strategy_position_buy, strategy_position_sell, real_position_buy, real_position_sell):
buy_vt_orderids = []
sell_vt_orderids = []

if strategy_position_buy > strategy_position_sell:
strategy_position_buy, strategy_position_sell = strategy_position_buy - strategy_position_sell, 0
elif strategy_position_buy < strategy_position_sell:
strategy_position_sell, strategy_position_buy = strategy_position_sell - strategy_position_buy, 0
elif strategy_position_buy is strategy_position_sell:
strategy_position_buy, strategy_position_sell = 0, 0

buy_price = min(now_price + offset_price, self.vt_symbols_limit_prices[market_vt_symbol].limit_up)
sell_price = max(now_price - offset_price, self.vt_symbols_limit_prices[market_vt_symbol].limit_down)

interval = " | "
print(market_vt_symbol, end=" ")
if strategy_position_buy > real_position_buy:

lot = TQZPositionData.tqz_risk_control(lot=strategy_position_buy - real_position_buy)
print(f'开多 {str(lot)} 手', end=" ")
buy_vt_orderids = self.buy(vt_symbol=market_vt_symbol, price=buy_price, volume=lot)
print(f'buy_result: {buy_vt_orderids}', end=interval)

elif strategy_position_buy < real_position_buy:

lot = TQZPositionData.tqz_risk_control(lot=real_position_buy - strategy_position_buy)
print(f'平多 {str(lot)} 手', end=" ")
buy_vt_orderids = self.sell(vt_symbol=market_vt_symbol, price=sell_price, volume=lot)
print(f'sell_result: {buy_vt_orderids}', end=interval)

elif strategy_position_buy is real_position_buy:
print("多单匹配 不处理", end=interval)

if strategy_position_sell > real_position_sell:

lot = TQZPositionData.tqz_risk_control(lot=strategy_position_sell - real_position_sell)
print(f'开空 {str(lot)} 手', end=" ")
sell_vt_orderids = self.short(vt_symbol=market_vt_symbol, price=sell_price, volume=lot)
print(f'short_result: {sell_vt_orderids}')

elif strategy_position_sell < real_position_sell:

lot = TQZPositionData.tqz_risk_control(lot=real_position_sell - strategy_position_sell)
print(f'平空 {str(lot)} 手', end=" ")
sell_vt_orderids = self.cover(vt_symbol=market_vt_symbol, price=buy_price, volume=lot)
print(f'cover_result: {sell_vt_orderids}')

elif strategy_position_sell is real_position_sell:
print("空单匹配 不处理")

return list(set(buy_vt_orderids + sell_vt_orderids))

def tqz_get_strategy_position_and_real_position(self, market_vt_symbol, strategy_data):
"""
get real position(buy, sell) and strategy position(buy, sell)
"""

# strategy position
strategy_position_buy = TQZSymbolOperator.tqz_get_strategy_position(
market_vt_symbol=market_vt_symbol,
direction=Direction.LONG,
strategy_data=strategy_data
)
strategy_position_sell = TQZSymbolOperator.tqz_get_strategy_position(
market_vt_symbol=market_vt_symbol,
direction=Direction.SHORT,
strategy_data=strategy_data
)

# real position
real_position_buy = self.tqz_get_real_position(
market_vt_symbol=market_vt_symbol,
direction=Direction.LONG
)
real_position_sell = self.tqz_get_real_position(
market_vt_symbol=market_vt_symbol,
direction=Direction.SHORT
)

return strategy_position_buy, strategy_position_sell, real_position_buy, real_position_sell

def tqz_get_current_cta_strategy_data(self):
""" """
return TQZPositionJsonOperator.tqz_load_jsonfile(jsonfile=self.strategy_engine.strategy_positions_all_path)

# ------ private part ------
def __tqz_strategy_is_real(self, strategy_position_buy, real_position_buy, strategy_position_sell, real_position_sell, futures_type: TQZFuturesType):
"""
strategy position(buy, sell) is real position(buy, sell) or not
"""

if futures_type in [TQZFuturesType.COMMODITY_FUTURES, TQZFuturesType.TREASURY_FUTURES]:
is_same = (strategy_position_buy is real_position_buy) and (strategy_position_sell is real_position_sell)
elif futures_type is TQZFuturesType.STOCK_INDEX_FUTURES:
is_same = (strategy_position_buy - strategy_position_sell) is (real_position_buy - real_position_sell)
else:
self.write_log("__tqz_strategy_is_real: futures_type is error.")
is_same = True

return is_same

举报

相关推荐

0 条评论