[增强] linux下ctp*.so, gw bug fix, float显示截短

This commit is contained in:
msincenselee 2020-03-27 21:39:30 +08:00
parent aa09f30f06
commit db6e107b95
21 changed files with 126 additions and 177 deletions

BIN
vnpy/api/ctp/vnctpmd.so Normal file

Binary file not shown.

BIN
vnpy/api/ctp/vnctptd.so Normal file

Binary file not shown.

View File

@ -311,7 +311,7 @@ class RestClient(object):
not_finished_executors = [i for i in self._executors if not i.done()] not_finished_executors = [i for i in self._executors if not i.done()]
self._executors = not_finished_executors self._executors = not_finished_executors
def _clean_finished_tasks(self, result = None): def _clean_finished_tasks(self, result=None):
with self._tasks_lock: with self._tasks_lock:
not_finished_tasks = [i for i in self._tasks if not i.ready()] not_finished_tasks = [i for i in self._tasks if not i.ready()]
self._tasks = not_finished_tasks self._tasks = not_finished_tasks

View File

@ -65,6 +65,7 @@ from vnpy.trader.util_logger import setup_logger
from vnpy.data.mongo.mongo_data import MongoData from vnpy.data.mongo.mongo_data import MongoData
from uuid import uuid1 from uuid import uuid1
class BackTestingEngine(object): class BackTestingEngine(object):
""" """
CTA回测引擎 CTA回测引擎
@ -106,7 +107,7 @@ class BackTestingEngine(object):
self.fix_commission = {} # 每手固定手续费 self.fix_commission = {} # 每手固定手续费
self.size = {} # 合约大小默认为1 self.size = {} # 合约大小默认为1
self.price_tick = {} # 价格最小变动 self.price_tick = {} # 价格最小变动
self.volume_tick = {} # 合约委托单最小单位 self.volume_tick = {} # 合约委托单最小单位
self.margin_rate = {} # 回测合约的保证金比率 self.margin_rate = {} # 回测合约的保证金比率
self.price_dict = {} # 登记vt_symbol对应的最新价 self.price_dict = {} # 登记vt_symbol对应的最新价
self.contract_dict = {} # 登记vt_symbol得对应合约信息 self.contract_dict = {} # 登记vt_symbol得对应合约信息
@ -207,7 +208,7 @@ class BackTestingEngine(object):
# 回测任务/回测结果,保存在数据库中 # 回测任务/回测结果,保存在数据库中
self.mongo_api = None self.mongo_api = None
self.task_id = None self.task_id = None
self.test_setting = None # 回测设置 self.test_setting = None # 回测设置
self.strategy_setting = None # 所有回测策略得设置 self.strategy_setting = None # 所有回测策略得设置
def create_fund_kline(self, name, use_renko=False): def create_fund_kline(self, name, use_renko=False):
@ -543,7 +544,7 @@ class BackTestingEngine(object):
for symbol, symbol_data in data_dict.items(): for symbol, symbol_data in data_dict.items():
self.write_log(u'配置{}数据:{}'.format(symbol, symbol_data)) self.write_log(u'配置{}数据:{}'.format(symbol, symbol_data))
self.set_price_tick(symbol, symbol_data.get('price_tick', 1)) self.set_price_tick(symbol, symbol_data.get('price_tick', 1))
self.set_volume_tick(symbol, symbol_data.get('min_volume',1)) self.set_volume_tick(symbol, symbol_data.get('min_volume', 1))
self.set_slippage(symbol, symbol_data.get('slippage', 0)) self.set_slippage(symbol, symbol_data.get('slippage', 0))
self.set_size(symbol, symbol_data.get('symbol_size', 10)) self.set_size(symbol, symbol_data.get('symbol_size', 10))
margin_rate = symbol_data.get('margin_rate', 0.1) margin_rate = symbol_data.get('margin_rate', 0.1)
@ -1664,7 +1665,7 @@ class BackTestingEngine(object):
for t in self.long_position_list: for t in self.long_position_list:
# 当前持仓的保证金 # 当前持仓的保证金
cur_occupy_money = min(self.get_price(t.vt_symbol), t.price) * abs(t.volume) * self.get_margin_rate( cur_occupy_money = min(self.get_price(t.vt_symbol), t.price) * abs(t.volume) * self.get_margin_rate(
t.vt_symbol) t.vt_symbol)
# 更新该合约短号的累计保证金 # 更新该合约短号的累计保证金
underly_symbol = get_underlying_symbol(t.symbol) underly_symbol = get_underlying_symbol(t.symbol)
@ -1680,7 +1681,8 @@ class BackTestingEngine(object):
if len(self.short_position_list) > 0: if len(self.short_position_list) > 0:
for t in self.short_position_list: for t in self.short_position_list:
# 当前空单保证金 # 当前空单保证金
cur_occupy_money = max(self.get_price(t.vt_symbol), t.price) * abs(t.volume) * self.get_margin_rate(t.vt_symbol) cur_occupy_money = max(self.get_price(t.vt_symbol), t.price) * abs(t.volume) * self.get_margin_rate(
t.vt_symbol)
# 该合约短号的累计空单保证金 # 该合约短号的累计空单保证金
underly_symbol = get_underlying_symbol(t.symbol) underly_symbol = get_underlying_symbol(t.symbol)
@ -1695,7 +1697,8 @@ class BackTestingEngine(object):
# 计算多空的保证金累加(对锁的取最大值) # 计算多空的保证金累加(对锁的取最大值)
for underly_symbol in occupy_underly_symbol_set: for underly_symbol in occupy_underly_symbol_set:
occupy_money += occupy_long_money_dict.get(underly_symbol, 0) + occupy_short_money_dict.get(underly_symbol, 0) occupy_money += occupy_long_money_dict.get(underly_symbol, 0) + occupy_short_money_dict.get(underly_symbol,
0)
# 可用资金 = 当前净值 - 占用保证金 # 可用资金 = 当前净值 - 占用保证金
self.avaliable = self.net_capital - occupy_money self.avaliable = self.net_capital - occupy_money
@ -2070,12 +2073,12 @@ class BackTestingEngine(object):
self.mongo_api = MongoData(host=save_mongo.get('host', 'localhost'), port=save_mongo.get('port', 27017)) self.mongo_api = MongoData(host=save_mongo.get('host', 'localhost'), port=save_mongo.get('port', 27017))
d = { d = {
'task_id': self.task_id, # 单实例回测任务id 'task_id': self.task_id, # 单实例回测任务id
'name': self.test_name, # 回测实例名称, 策略名+参数+时间 'name': self.test_name, # 回测实例名称, 策略名+参数+时间
'group_id': self.test_setting.get('group_id', datetime.now().strftime('%y-%m-%d')), # 回测组合id 'group_id': self.test_setting.get('group_id', datetime.now().strftime('%y-%m-%d')), # 回测组合id
'status': 'start', 'status': 'start',
'task_start_time': datetime.now(), # 任务开始执行时间 'task_start_time': datetime.now(), # 任务开始执行时间
'run_host': socket.gethostname(), # 任务运行得host主机 'run_host': socket.gethostname(), # 任务运行得host主机
'test_setting': self.test_setting, # 回测参数 'test_setting': self.test_setting, # 回测参数
'strategy_setting': self.strategy_setting, # 策略参数 'strategy_setting': self.strategy_setting, # 策略参数
} }
@ -2135,11 +2138,11 @@ class BackTestingEngine(object):
flt=flt) flt=flt)
if d: if d:
d.update({'status': 'finish'}) # 更新状态未完成 d.update({'status': 'finish'}) # 更新状态未完成
d.update(result_info) # 补充回测结果 d.update(result_info) # 补充回测结果
d.update({'task_finish_time': datetime.now()}) # 更新回测完成时间 d.update({'task_finish_time': datetime.now()}) # 更新回测完成时间
d.update({'trade_list': binary.Binary(zlib.compress(pickle.dumps(self.trade_pnl_list)))}) # 更新交易记录 d.update({'trade_list': binary.Binary(zlib.compress(pickle.dumps(self.trade_pnl_list)))}) # 更新交易记录
d.update({'daily_list': binary.Binary(zlib.compress(pickle.dumps(self.daily_list)))}) # 更新每日净值记录 d.update({'daily_list': binary.Binary(zlib.compress(pickle.dumps(self.daily_list)))}) # 更新每日净值记录
self.write_log(u'更新回测结果至数据库') self.write_log(u'更新回测结果至数据库')

View File

@ -344,7 +344,6 @@ class CtaEngine(BaseEngine):
holding = self.get_position_holding(position.vt_symbol, position.gateway_name) holding = self.get_position_holding(position.vt_symbol, position.gateway_name)
holding.update_position(position) holding.update_position(position)
def check_unsubscribed_symbols(self): def check_unsubscribed_symbols(self):
"""检查未订阅合约""" """检查未订阅合约"""
@ -1179,7 +1178,7 @@ class CtaEngine(BaseEngine):
self.write_log(msg) self.write_log(msg)
return True, msg return True, msg
def save_strategy_data(self, select_name: str): def save_strategy_data(self, select_name: str = 'ALL'):
""" save strategy data""" """ save strategy data"""
has_executed = False has_executed = False
msg = "" msg = ""
@ -1215,7 +1214,7 @@ class CtaEngine(BaseEngine):
self.write_error(u'保存策略{}数据异常:'.format(strategy_name, str(ex))) self.write_error(u'保存策略{}数据异常:'.format(strategy_name, str(ex)))
self.write_error(traceback.format_exc()) self.write_error(traceback.format_exc())
def save_strategy_snapshot(self, select_name: str): def save_strategy_snapshot(self, select_name: str = 'ALL'):
""" """
保存策略K线切片数据 保存策略K线切片数据
:param select_name: :param select_name:
@ -1607,7 +1606,7 @@ class CtaEngine(BaseEngine):
try: try:
from vnpy.trader.util_wechat import send_wx_msg from vnpy.trader.util_wechat import send_wx_msg
send_wx_msg(content=msg) send_wx_msg(content=msg)
except Exception as ex: except Exception: # noqa
pass pass
ret_msg = u'持仓不匹配: {}' \ ret_msg = u'持仓不匹配: {}' \
.format(pos_compare_result) .format(pos_compare_result)

View File

@ -13,9 +13,6 @@ import gc
import pandas as pd import pandas as pd
import traceback import traceback
import random import random
import bz2
import pickle
from datetime import datetime, timedelta from datetime import datetime, timedelta
from time import sleep from time import sleep
@ -196,7 +193,6 @@ class PortfolioTestingEngine(BackTestingEngine):
symbol, exchange = extract_vt_symbol(vt_symbol) symbol, exchange = extract_vt_symbol(vt_symbol)
self.load_bar_csv_to_df(vt_symbol, self.bar_csv_file.get(symbol)) self.load_bar_csv_to_df(vt_symbol, self.bar_csv_file.get(symbol))
# 合并数据 # 合并数据
self.comine_bar_df() self.comine_bar_df()
@ -309,6 +305,7 @@ class PortfolioTestingEngine(BackTestingEngine):
traceback.print_exc() traceback.print_exc()
return return
def single_test(test_setting: dict, strategy_setting: dict): def single_test(test_setting: dict, strategy_setting: dict):
""" """
单一回测 单一回测

View File

@ -16,11 +16,9 @@ from vnpy.trader.constant import Interval, Direction, Offset, Status, OrderType
from vnpy.trader.object import BarData, TickData, OrderData, TradeData from vnpy.trader.object import BarData, TickData, OrderData, TradeData
from vnpy.trader.utility import virtual, append_data, extract_vt_symbol, get_underlying_symbol from vnpy.trader.utility import virtual, append_data, extract_vt_symbol, get_underlying_symbol
from .base import StopOrder, EngineType from .base import StopOrder
from vnpy.component.cta_grid_trade import CtaGrid, CtaGridTrade, LOCK_GRID from vnpy.component.cta_grid_trade import CtaGrid, CtaGridTrade
from vnpy.component.cta_position import CtaPosition from vnpy.component.cta_position import CtaPosition
from vnpy.component.cta_policy import CtaPolicy # noqa
class CtaTemplate(ABC): class CtaTemplate(ABC):
"""CTA策略模板""" """CTA策略模板"""
@ -416,8 +414,6 @@ class CtaTemplate(ABC):
self.cta_engine.sync_strategy_data(self) self.cta_engine.sync_strategy_data(self)
class CtaFutureTemplate(CtaTemplate): class CtaFutureTemplate(CtaTemplate):
""" """
合约期货模板 合约期货模板
@ -426,7 +422,7 @@ class CtaFutureTemplate(CtaTemplate):
price_tick = 1 # 商品的最小价格跳动 price_tick = 1 # 商品的最小价格跳动
symbol_size = 10 # 商品得合约乘数 symbol_size = 10 # 商品得合约乘数
margin_rate = 0.1 # 商品的保证金 margin_rate = 0.1 # 商品的保证金
volumn_tick = 1 # 商品最小成交数量 volumn_tick = 1 # 商品最小成交数量
# 委托类型 # 委托类型
order_type = OrderType.LIMIT order_type = OrderType.LIMIT
@ -441,7 +437,7 @@ class CtaFutureTemplate(CtaTemplate):
backtesting = False backtesting = False
# 逻辑过程日志 # 逻辑过程日志
dist_fieldnames = ['datetime', 'symbol', 'volume', 'price','margin', dist_fieldnames = ['datetime', 'symbol', 'volume', 'price', 'margin',
'operation', 'signal', 'stop_price', 'target_price', 'operation', 'signal', 'stop_price', 'target_price',
'long_pos', 'short_pos'] 'long_pos', 'short_pos']
@ -844,37 +840,7 @@ class CtaFutureTemplate(CtaTemplate):
self.active_orders.pop(order.vt_orderid, None) self.active_orders.pop(order.vt_orderid, None)
return return
order_price = old_order['price']
order_type = old_order.get('order_type', OrderType.LIMIT)
order_retry = old_order.get('retry', 0)
grid = old_order.get('grid', None) grid = old_order.get('grid', None)
if order_retry > 20:
# 这里超过20次尝试失败后不再尝试,发出告警信息
msg = u'{} {}/{}手, 重试开仓次数{}>20' \
.format(self.strategy_name,
order_vt_symbol,
order_volume,
order_retry)
self.write_error(msg)
self.send_wechat(msg)
if grid:
if order.vt_orderid in grid.order_ids:
grid.order_ids.remove(order.vt_orderid)
# 网格的所有委托单已经执行完毕
if len(grid.order_ids) == 0:
grid.order_status = False
self.gt.save()
self.write_log(u'网格信息更新:{}'.format(grid.__dict__))
self.write_log(u'移除:{}'.format(order.vt_orderid))
self.active_orders.pop(order.vt_orderid, None)
return
order_retry += 1
pre_status = old_order.get('status', Status.NOTTRADED) pre_status = old_order.get('status', Status.NOTTRADED)
old_order.update({'status': Status.CANCELLED}) old_order.update({'status': Status.CANCELLED})
self.write_log(u'委托单状态:{}=>{}'.format(pre_status, old_order.get('status'))) self.write_log(u'委托单状态:{}=>{}'.format(pre_status, old_order.get('status')))
@ -918,29 +884,7 @@ class CtaFutureTemplate(CtaTemplate):
self.active_orders.pop(order.vt_orderid, None) self.active_orders.pop(order.vt_orderid, None)
return return
order_price = old_order['price']
order_type = old_order.get('order_type', OrderType.LIMIT)
order_retry = old_order.get('retry', 1)
grid = old_order.get('grid', None) grid = old_order.get('grid', None)
if order_retry > 20:
msg = u'{} 平仓撤单 {}/{}手, 重试平仓次数{}>20' \
.format(self.strategy_name, order_symbol, order_volume, order_retry)
self.write_error(msg)
self.send_wechat(msg)
if grid:
if order.vt_orderid in grid.order_ids:
grid.order_ids.remove(order.vt_orderid)
if not grid.order_ids:
grid.order_status = False
self.gt.save()
self.write_log(u'更新网格=>{}'.format(grid.__dict__))
self.write_log(u'移除活动订单:{}'.format(order.vt_orderid))
self.active_orders.pop(order.vt_orderid, None)
return
order_retry += 1
pre_status = old_order.get('status', Status.NOTTRADED) pre_status = old_order.get('status', Status.NOTTRADED)
old_order.update({'status': Status.CANCELLED}) old_order.update({'status': Status.CANCELLED})
self.write_log(u'委托单状态:{}=>{}'.format(pre_status, old_order.get('status'))) self.write_log(u'委托单状态:{}=>{}'.format(pre_status, old_order.get('status')))
@ -957,7 +901,6 @@ class CtaFutureTemplate(CtaTemplate):
def on_stop_order(self, stop_order: StopOrder): def on_stop_order(self, stop_order: StopOrder):
self.write_log(f'停止单触发:{stop_order.__dict__}') self.write_log(f'停止单触发:{stop_order.__dict__}')
def grid_check_stop(self): def grid_check_stop(self):
""" """
网格逐一止损/止盈检查 (根据指数价格进行止损止盈 网格逐一止损/止盈检查 (根据指数价格进行止损止盈
@ -976,12 +919,12 @@ class CtaFutureTemplate(CtaTemplate):
if g.stop_price > 0 and g.stop_price > self.cur_price and g.open_status and not g.order_status: if g.stop_price > 0 and g.stop_price > self.cur_price and g.open_status and not g.order_status:
# 调用平仓模块 # 调用平仓模块
self.write_log(u'{} {}当前价:{} 触发多单止损线{},开仓价:{},v{}'. self.write_log(u'{} {}当前价:{} 触发多单止损线{},开仓价:{},v{}'.
format(self.cur_datetime, format(self.cur_datetime,
self.vt_symbol, self.vt_symbol,
self.cur_price, self.cur_price,
g.stop_price, g.stop_price,
g.open_price, g.open_price,
g.volume)) g.volume))
if self.grid_sell(g): if self.grid_sell(g):
self.write_log(u'多单止盈/止损委托成功') self.write_log(u'多单止盈/止损委托成功')
else: else:
@ -993,8 +936,8 @@ class CtaFutureTemplate(CtaTemplate):
if g.stop_price > 0 and g.stop_price < self.cur_price and g.open_status and not g.order_status: if g.stop_price > 0 and g.stop_price < self.cur_price and g.open_status and not g.order_status:
# 网格止损 # 网格止损
self.write_log(u'{} {}当前价:{} 触发空单止损线:{}, 开仓价:{},v{}'. self.write_log(u'{} {}当前价:{} 触发空单止损线:{}, 开仓价:{},v{}'.
format(self.cur_datetime, self.vt_symbol, self.cur_price, g.stop_price, format(self.cur_datetime, self.vt_symbol, self.cur_price, g.stop_price,
g.open_price, g.volume)) g.open_price, g.volume))
if self.grid_cover(g): if self.grid_cover(g):
self.write_log(u'空单止盈/止损委托成功') self.write_log(u'空单止盈/止损委托成功')
else: else:
@ -1013,16 +956,15 @@ class CtaFutureTemplate(CtaTemplate):
grid=grid) grid=grid)
if len(vt_orderids) > 0: if len(vt_orderids) > 0:
self.write_log(u'创建{}事务多单,开仓价:{},数量:{},止盈价:{},止损价:{}' self.write_log(u'创建{}事务多单,开仓价:{},数量:{},止盈价:{},止损价:{}'
.format(grid.type, grid.open_price, grid.volume, grid.close_price, grid.stop_price)) .format(grid.type, grid.open_price, grid.volume, grid.close_price, grid.stop_price))
self.gt.dn_grids.append(grid) self.gt.dn_grids.append(grid)
self.gt.save() self.gt.save()
return True return True
else: else:
self.write_error(u'创建{}事务多单,委托失败,开仓价:{},数量:{},止盈价:{}' self.write_error(u'创建{}事务多单,委托失败,开仓价:{},数量:{},止盈价:{}'
.format(grid.type, grid.open_price, grid.volume, grid.close_price)) .format(grid.type, grid.open_price, grid.volume, grid.close_price))
return False return False
def grid_short(self, grid): def grid_short(self, grid):
""" """
事务开空仓 事务开空仓
@ -1036,14 +978,14 @@ class CtaFutureTemplate(CtaTemplate):
grid=grid) grid=grid)
if len(vt_orderids) > 0: if len(vt_orderids) > 0:
self.write_log(u'创建{}事务空单,指数开空价:{},主力开仓价:{},数量:{},止盈价:{},止损价:{}' self.write_log(u'创建{}事务空单,指数开空价:{},主力开仓价:{},数量:{},止盈价:{},止损价:{}'
.format(grid.type, grid.open_price, self.cur_price, grid.volume, grid.close_price, .format(grid.type, grid.open_price, self.cur_price, grid.volume, grid.close_price,
grid.stop_price)) grid.stop_price))
self.gt.up_grids.append(grid) self.gt.up_grids.append(grid)
self.gt.save() self.gt.save()
return True return True
else: else:
self.write_error(u'创建{}事务空单,委托失败,开仓价:{},数量:{},止盈价:{}' self.write_error(u'创建{}事务空单,委托失败,开仓价:{},数量:{},止盈价:{}'
.format(grid.type, grid.open_price, grid.volume, grid.close_price)) .format(grid.type, grid.open_price, grid.volume, grid.close_price))
return False return False
def grid_sell(self, grid): def grid_sell(self, grid):
@ -1302,7 +1244,6 @@ class CtaFutureTemplate(CtaTemplate):
if len(self.active_orders) == 0: if len(self.active_orders) == 0:
self.entrust = 0 self.entrust = 0
def display_grids(self): def display_grids(self):
"""更新网格显示信息""" """更新网格显示信息"""
if not self.inited: if not self.inited:
@ -1340,7 +1281,9 @@ class CtaFutureTemplate(CtaTemplate):
save_path = self.cta_engine.get_data_path() save_path = self.cta_engine.get_data_path()
try: try:
if 'margin' not in dist_data: if 'margin' not in dist_data:
dist_data.update({'margin': dist_data.get('price', 0) * dist_data.get('volume', 0) * self.cta_engine.get_margin_rate(dist_data.get('symbol', self.vt_symbol))}) dist_data.update({'margin': dist_data.get('price', 0) * dist_data.get('volume',
0) * self.cta_engine.get_margin_rate(
dist_data.get('symbol', self.vt_symbol))})
if self.position and 'long_pos' not in dist_data: if self.position and 'long_pos' not in dist_data:
dist_data.update({'long_pos': self.position.long_pos}) dist_data.update({'long_pos': self.position.long_pos})
if self.position and 'short_pos' not in dist_data: if self.position and 'short_pos' not in dist_data:
@ -1373,5 +1316,3 @@ class CtaFutureTemplate(CtaTemplate):
if self.backtesting: if self.backtesting:
return return
self.cta_engine.send_wechat(msg=msg, strategy=self) self.cta_engine.send_wechat(msg=msg, strategy=self)

View File

@ -14,7 +14,11 @@ from .template import (
BarData, BarData,
TradeData, TradeData,
OrderData, OrderData,
CtaTemplate, CtaSignal, TargetPosTemplate, CtaProTemplate, CtaProFutureTemplate) # noqa CtaTemplate,
CtaSignal,
TargetPosTemplate,
CtaProTemplate,
CtaProFutureTemplate) # noqa
from vnpy.trader.utility import BarGenerator, ArrayManager # noqa from vnpy.trader.utility import BarGenerator, ArrayManager # noqa
from .template_spread import CtaSpreadTemplate from .template_spread import CtaSpreadTemplate

View File

@ -715,7 +715,9 @@ class CtaEngine(BaseEngine):
strategy = self.strategies.get(strategy_name, None) strategy = self.strategies.get(strategy_name, None)
if not strategy: if not strategy:
return False return False
if len(vt_symbol) == 0:
self.write_error(f'不能为{strategy_name}订阅空白合约')
return False
contract = self.main_engine.get_contract(vt_symbol) contract = self.main_engine.get_contract(vt_symbol)
if contract: if contract:
if contract.gateway_name and not gateway_name: if contract.gateway_name and not gateway_name:
@ -1101,7 +1103,7 @@ class CtaEngine(BaseEngine):
self.write_log(msg) self.write_log(msg)
return True, msg return True, msg
def save_strategy_data(self, select_name: str): def save_strategy_data(self, select_name: str = 'ALL'):
""" save strategy data""" """ save strategy data"""
has_executed = False has_executed = False
msg = "" msg = ""
@ -1137,7 +1139,7 @@ class CtaEngine(BaseEngine):
self.write_error(u'保存策略{}数据异常:'.format(strategy_name, str(ex))) self.write_error(u'保存策略{}数据异常:'.format(strategy_name, str(ex)))
self.write_error(traceback.format_exc()) self.write_error(traceback.format_exc())
def save_strategy_snapshot(self, select_name: str): def save_strategy_snapshot(self, select_name: str = 'ALL'):
""" """
保存策略K线切片数据 保存策略K线切片数据
:param select_name: :param select_name:
@ -1571,7 +1573,7 @@ class CtaEngine(BaseEngine):
try: try:
from vnpy.trader.util_wechat import send_wx_msg from vnpy.trader.util_wechat import send_wx_msg
send_wx_msg(content=msg) send_wx_msg(content=msg)
except Exception as ex: except Exception as ex: # noqa
pass pass
ret_msg = u'持仓不匹配: {}' \ ret_msg = u'持仓不匹配: {}' \
.format(pos_compare_result) .format(pos_compare_result)

View File

@ -1568,7 +1568,8 @@ class CtaProFutureTemplate(CtaProTemplate):
over_seconds = (dt - order_time).total_seconds() over_seconds = (dt - order_time).total_seconds()
# 只处理未成交的限价委托单 # 只处理未成交的限价委托单
if order_status in [Status.NOTTRADED,Status.SUBMITTING] and (order_type == OrderType.LIMIT or '.SPD' in order_vt_symbol): if order_status in [Status.NOTTRADED, Status.SUBMITTING] and (
order_type == OrderType.LIMIT or '.SPD' in order_vt_symbol):
if over_seconds > self.cancel_seconds or force: # 超过设置的时间还未成交 if over_seconds > self.cancel_seconds or force: # 超过设置的时间还未成交
self.write_log(u'超时{}秒未成交取消委托单vt_orderid:{},order:{}' self.write_log(u'超时{}秒未成交取消委托单vt_orderid:{},order:{}'
.format(over_seconds, vt_orderid, order_info)) .format(over_seconds, vt_orderid, order_info))

View File

@ -98,7 +98,7 @@ class RpcEngine(BaseEngine):
self.save_setting() self.save_setting()
self.write_log("RPC服务启动成功") self.write_log("RPC服务启动成功")
return True,"RPC服务启动成功" return True, "RPC服务启动成功"
def stop(self): def stop(self):
"""""" """"""

View File

@ -3353,10 +3353,10 @@ class CtaLineBar(object):
# 记录所有SK的顶部和底部 # 记录所有SK的顶部和底部
# 峰(顶部) # 峰(顶部)
if self.line_sk[-1] < self.line_sk[-2] and self.line_sk[-3] < self.line_sk[-2]: if self.line_sk[-1] < self.line_sk[-2] and self.line_sk[-3] < self.line_sk[-2]:
t = {} t = dict()
t['type'] = u'T' t['type'] = u'T'
t['sk'] = self.line_sk[-2] t['sk'] = self.line_sk[-2]
t['price'] = max([self.high_array[-4:]]) t['price'] = max(self.high_array[-4:])
t['time'] = self.line_bar[-1].datetime t['time'] = self.line_bar[-1].datetime
t['bars'] = 0 t['bars'] = 0
if len(self.skd_top_list) > self.max_hold_bars: if len(self.skd_top_list) > self.max_hold_bars:
@ -3369,10 +3369,10 @@ class CtaLineBar(object):
# 谷(底部) # 谷(底部)
elif self.line_sk[-1] > self.line_sk[-2] and self.line_sk[-3] > self.line_sk[-2]: elif self.line_sk[-1] > self.line_sk[-2] and self.line_sk[-3] > self.line_sk[-2]:
b = {} b = dict()
b['type'] = u'B' b['type'] = u'B'
b['sk'] = self.line_sk[-2] b['sk'] = self.line_sk[-2]
b['price'] = min([bar.low_price for bar in self.line_bar[-4:]]) b['price'] = min(self.low_array[-4:])
b['time'] = self.line_bar[-1].datetime b['time'] = self.line_bar[-1].datetime
b['bars'] = 0 b['bars'] = 0
if len(self.skd_buttom_list) > self.max_hold_bars: if len(self.skd_buttom_list) > self.max_hold_bars:

View File

@ -81,7 +81,6 @@ class CtaPosition(CtaComponent):
self.write_log(f'多仓:{pre_long_pos}->{self.long_pos}') self.write_log(f'多仓:{pre_long_pos}->{self.long_pos}')
self.write_log(f'净:{pre_pos}->{self.pos}') self.write_log(f'净:{pre_pos}->{self.pos}')
return True return True
def clear(self): def clear(self):

View File

@ -201,7 +201,7 @@ class BinanceFutureData(RestClient):
"name": name, "name": name,
"price_tick": pricetick, "price_tick": pricetick,
"symbol_size": 20, "symbol_size": 20,
"margin_rate" : round(float(d['requiredMarginPercent']) / 100,5), "margin_rate": round(float(d['requiredMarginPercent']) / 100, 5),
"min_volume": min_volume, "min_volume": min_volume,
"product": Product.FUTURES.value, "product": Product.FUTURES.value,
"commission_rate": 0.005 "commission_rate": 0.005
@ -218,7 +218,6 @@ class BinanceFutureData(RestClient):
contracts = load_json(f, auto_save=False) contracts = load_json(f, auto_save=False)
return contracts return contracts
def save_contracts(self): def save_contracts(self):
"""保存合约配置""" """保存合约配置"""
contracts = self.get_contracts() contracts = self.get_contracts()

View File

@ -37,7 +37,6 @@ from vnpy.trader.object import (
from vnpy.trader.event import EVENT_TIMER from vnpy.trader.event import EVENT_TIMER
from vnpy.event import Event from vnpy.event import Event
REST_HOST = "https://www.binance.com" REST_HOST = "https://www.binance.com"
WEBSOCKET_TRADE_HOST = "wss://stream.binance.com:9443/ws/" WEBSOCKET_TRADE_HOST = "wss://stream.binance.com:9443/ws/"
WEBSOCKET_DATA_HOST = "wss://stream.binance.com:9443/stream?streams=" WEBSOCKET_DATA_HOST = "wss://stream.binance.com:9443/stream?streams="
@ -159,6 +158,7 @@ class BinanceGateway(BaseGateway):
and self.status.get('mdws_con', False): and self.status.get('mdws_con', False):
self.status.update({'con': True}) self.status.update({'con': True})
class BinanceRestApi(RestClient): class BinanceRestApi(RestClient):
""" """
BINANCE REST API BINANCE REST API
@ -234,12 +234,12 @@ class BinanceRestApi(RestClient):
return request return request
def connect( def connect(
self, self,
key: str, key: str,
secret: str, secret: str,
session_number: int, session_number: int,
proxy_host: str, proxy_host: str,
proxy_port: int proxy_port: int
): ):
""" """
Initialize connection to REST server. Initialize connection to REST server.
@ -250,7 +250,7 @@ class BinanceRestApi(RestClient):
self.proxy_host = proxy_host self.proxy_host = proxy_host
self.connect_time = ( self.connect_time = (
int(datetime.now().strftime("%y%m%d%H%M%S")) * self.order_count int(datetime.now().strftime("%y%m%d%H%M%S")) * self.order_count
) )
self.init(REST_HOST, proxy_host, proxy_port) self.init(REST_HOST, proxy_host, proxy_port)
@ -504,7 +504,7 @@ class BinanceRestApi(RestClient):
self.gateway.write_log(msg) self.gateway.write_log(msg)
def on_send_order_error( def on_send_order_error(
self, exception_type: type, exception_value: Exception, tb, request: Request self, exception_type: type, exception_value: Exception, tb, request: Request
): ):
""" """
Callback when sending order caused exception. Callback when sending order caused exception.
@ -545,13 +545,13 @@ class BinanceRestApi(RestClient):
"symbol": req.symbol, "symbol": req.symbol,
"interval": INTERVAL_VT2BINANCE[req.interval], "interval": INTERVAL_VT2BINANCE[req.interval],
"limit": limit, "limit": limit,
"startTime": start_time * 1000, # convert to millisecond "startTime": start_time * 1000, # convert to millisecond
} }
# Add end time if specified # Add end time if specified
if req.end: if req.end:
end_time = int(datetime.timestamp(req.end)) end_time = int(datetime.timestamp(req.end))
params["endTime"] = end_time * 1000 # convert to millisecond params["endTime"] = end_time * 1000 # convert to millisecond
# Get response from server # Get response from server
resp = self.request( resp = self.request(
@ -576,7 +576,7 @@ class BinanceRestApi(RestClient):
buf = [] buf = []
for l in data: for l in data:
dt = datetime.fromtimestamp(l[0] / 1000) # convert to second dt = datetime.fromtimestamp(l[0] / 1000) # convert to second
bar = BarData( bar = BarData(
symbol=req.symbol, symbol=req.symbol,

View File

@ -212,7 +212,6 @@ class BinancefRestApi(RestClient):
self.orders = {} self.orders = {}
def sign(self, request: Request) -> Request: def sign(self, request: Request) -> Request:
""" """
Generate BINANCE signature. Generate BINANCE signature.
@ -262,13 +261,13 @@ class BinancefRestApi(RestClient):
return request return request
def connect( def connect(
self, self,
key: str, key: str,
secret: str, secret: str,
session_number: int, session_number: int,
server: str, server: str,
proxy_host: str, proxy_host: str,
proxy_port: int proxy_port: int
) -> None: ) -> None:
""" """
Initialize connection to REST server. Initialize connection to REST server.
@ -280,7 +279,7 @@ class BinancefRestApi(RestClient):
self.server = server self.server = server
self.connect_time = ( self.connect_time = (
int(datetime.now().strftime("%y%m%d%H%M%S")) * self.order_count int(datetime.now().strftime("%y%m%d%H%M%S")) * self.order_count
) )
if self.server == "REAL": if self.server == "REAL":
@ -306,7 +305,6 @@ class BinancefRestApi(RestClient):
# 添加到定时查询队列中 # 添加到定时查询队列中
self.gateway.query_functions = [self.query_account, self.query_position] self.gateway.query_functions = [self.query_account, self.query_position]
def query_time(self) -> Request: def query_time(self) -> Request:
"""""" """"""
data = { data = {
@ -366,12 +364,11 @@ class BinancefRestApi(RestClient):
data=data data=data
) )
def query_trade(self, vt_symbol: str = '') -> Request: def query_trade(self, vt_symbol: str = '') -> Request:
"""""" """"""
data = {"security": Security.SIGNED} data = {"security": Security.SIGNED}
if vt_symbol: if vt_symbol:
if '.' in vt_symbol: if '.' in vt_symbol:
vt_symbol = vt_symbol.split('.')[0] vt_symbol = vt_symbol.split('.')[0]
data.update({'symbol': vt_symbol}) data.update({'symbol': vt_symbol})
@ -607,7 +604,6 @@ class BinancefRestApi(RestClient):
self.gateway.write_log("委托信息查询成功") self.gateway.write_log("委托信息查询成功")
def on_query_trade(self, data: dict, request: Request) -> None: def on_query_trade(self, data: dict, request: Request) -> None:
"""""" """"""
for d in data: for d in data:
@ -624,6 +620,7 @@ class BinancefRestApi(RestClient):
price=float(d["price"]), price=float(d["price"]),
volume=float(d['qty']), volume=float(d['qty']),
time=time, time=time,
datetime=dt,
gateway_name=self.gateway_name, gateway_name=self.gateway_name,
) )
self.gateway.on_trade(trade) self.gateway.on_trade(trade)
@ -664,7 +661,7 @@ class BinancefRestApi(RestClient):
name=name, name=name,
pricetick=pricetick, pricetick=pricetick,
size=symbol_size, size=symbol_size,
margin_rate= round(float(d['requiredMarginPercent'])/100, 5), margin_rate=round(float(d['requiredMarginPercent']) / 100, 5),
min_volume=min_volume, min_volume=min_volume,
product=Product.FUTURES, product=Product.FUTURES,
history_data=True, history_data=True,
@ -692,7 +689,7 @@ class BinancefRestApi(RestClient):
self.gateway.write_log(msg) self.gateway.write_log(msg)
def on_send_order_error( def on_send_order_error(
self, exception_type: type, exception_value: Exception, tb, request: Request self, exception_type: type, exception_value: Exception, tb, request: Request
) -> None: ) -> None:
""" """
Callback when sending order caused exception. Callback when sending order caused exception.
@ -738,13 +735,13 @@ class BinancefRestApi(RestClient):
"symbol": req.symbol, "symbol": req.symbol,
"interval": INTERVAL_VT2BINANCEF[req.interval], "interval": INTERVAL_VT2BINANCEF[req.interval],
"limit": limit, "limit": limit,
"startTime": start_time * 1000, # convert to millisecond "startTime": start_time * 1000, # convert to millisecond
} }
# Add end time if specified # Add end time if specified
if req.end: if req.end:
end_time = int(datetime.timestamp(req.end)) end_time = int(datetime.timestamp(req.end))
params["endTime"] = end_time * 1000 # convert to millisecond params["endTime"] = end_time * 1000 # convert to millisecond
# Get response from server # Get response from server
resp = self.request( resp = self.request(
@ -769,7 +766,7 @@ class BinancefRestApi(RestClient):
buf = [] buf = []
for l in data: for l in data:
dt = datetime.fromtimestamp(l[0] / 1000) # convert to second dt = datetime.fromtimestamp(l[0] / 1000) # convert to second
bar = BarData( bar = BarData(
symbol=req.symbol, symbol=req.symbol,
@ -910,6 +907,7 @@ class BinancefTradeWebsocketApi(WebsocketClient):
price=float(ord_data["L"]), price=float(ord_data["L"]),
volume=trade_volume, volume=trade_volume,
time=trade_time, time=trade_time,
datetime=trade_time,
gateway_name=self.gateway_name, gateway_name=self.gateway_name,
) )
self.gateway.on_trade(trade) self.gateway.on_trade(trade)
@ -928,10 +926,10 @@ class BinancefDataWebsocketApi(WebsocketClient):
self.ticks: Dict[str, TickData] = {} self.ticks: Dict[str, TickData] = {}
def connect( def connect(
self, self,
proxy_host: str, proxy_host: str,
proxy_port: int, proxy_port: int,
server: str server: str
) -> None: ) -> None:
"""""" """"""
self.proxy_host = proxy_host self.proxy_host = proxy_host

View File

@ -1,7 +1,6 @@
""" """
""" """
import os
import sys import sys
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from typing import Any, Sequence, Dict, List, Optional, Callable from typing import Any, Sequence, Dict, List, Optional, Callable
@ -324,6 +323,7 @@ class BaseGateway(ABC):
""" """
return self.status return self.status
class LocalOrderManager: class LocalOrderManager:
""" """
Management tool to support use local order id for trading. Management tool to support use local order id for trading.

View File

@ -48,6 +48,8 @@ class BaseCell(QtWidgets.QTableWidgetItem):
Set text content. Set text content.
""" """
self.setText(str(content)) self.setText(str(content))
if isinstance(data, float):
data = round(data, 7)
self._data = data self._data = data
def get_data(self) -> Any: def get_data(self) -> Any:
@ -737,36 +739,36 @@ class TradingWidget(QtWidgets.QWidget):
if not self.checkFixed.isChecked(): if not self.checkFixed.isChecked():
self.price_line.setText(str(tick.last_price)) self.price_line.setText(str(tick.last_price))
self.lp_label.setText(str(tick.last_price)) self.lp_label.setText(str(round(tick.last_price, 7)))
self.bp1_label.setText(str(tick.bid_price_1)) self.bp1_label.setText(str(round(tick.bid_price_1, 7)))
self.bv1_label.setText(str(tick.bid_volume_1)) self.bv1_label.setText(str(round(tick.bid_volume_1, 7)))
self.ap1_label.setText(str(tick.ask_price_1)) self.ap1_label.setText(str(round(tick.ask_price_1, 7)))
self.av1_label.setText(str(tick.ask_volume_1)) self.av1_label.setText(str(round(tick.ask_volume_1, 7)))
if tick.pre_close: if tick.pre_close:
r = (tick.last_price / tick.pre_close - 1) * 100 r = (tick.last_price / tick.pre_close - 1) * 100
self.return_label.setText(f"{r:.2f}%") self.return_label.setText(f"{r:.2f}%")
if tick.bid_price_2: if tick.bid_price_2:
self.bp2_label.setText(str(tick.bid_price_2)) self.bp2_label.setText(str(round(tick.bid_price_2), 7))
self.bv2_label.setText(str(tick.bid_volume_2)) self.bv2_label.setText(str(round(tick.bid_volume_2, 7)))
self.ap2_label.setText(str(tick.ask_price_2)) self.ap2_label.setText(str(round(tick.ask_price_2, 7)))
self.av2_label.setText(str(tick.ask_volume_2)) self.av2_label.setText(str(round(tick.ask_volume_2, 7)))
self.bp3_label.setText(str(tick.bid_price_3)) self.bp3_label.setText(str(round(tick.bid_price_3, 7)))
self.bv3_label.setText(str(tick.bid_volume_3)) self.bv3_label.setText(str(round(tick.bid_volume_3, 7)))
self.ap3_label.setText(str(tick.ask_price_3)) self.ap3_label.setText(str(round(tick.ask_price_3, 7)))
self.av3_label.setText(str(tick.ask_volume_3)) self.av3_label.setText(str(round(tick.ask_volume_3, 7)))
self.bp4_label.setText(str(tick.bid_price_4)) self.bp4_label.setText(str(round(tick.bid_price_4, 7)))
self.bv4_label.setText(str(tick.bid_volume_4)) self.bv4_label.setText(str(round(tick.bid_volume_4, 7)))
self.ap4_label.setText(str(tick.ask_price_4)) self.ap4_label.setText(str(round(tick.ask_price_4, 7)))
self.av4_label.setText(str(tick.ask_volume_4)) self.av4_label.setText(str(round(tick.ask_volume_4, 7)))
self.bp5_label.setText(str(tick.bid_price_5)) self.bp5_label.setText(str(round(tick.bid_price_5, 7)))
self.bv5_label.setText(str(tick.bid_volume_5)) self.bv5_label.setText(str(round(tick.bid_volume_5, 7)))
self.ap5_label.setText(str(tick.ask_price_5)) self.ap5_label.setText(str(round(tick.ask_price_5, 7)))
self.av5_label.setText(str(tick.ask_volume_5)) self.av5_label.setText(str(round(tick.ask_volume_5, 7)))
def set_vt_symbol(self) -> None: def set_vt_symbol(self) -> None:
""" """

View File

@ -1,9 +1,8 @@
# encoding: UTF-8 # encoding: UTF-8
# 华富资产 # 华富资产
import os
from collections import OrderedDict from typing import Dict
from typing import Any, Dict
from .utility import get_folder_path from .utility import get_folder_path
from .util_logger import setup_logger from .util_logger import setup_logger
@ -83,6 +82,7 @@ class LogMonitor(BasicMonitor):
def __init__(self, event_engine=None, monitor_name='LogMonitor'): def __init__(self, event_engine=None, monitor_name='LogMonitor'):
super().__init__(event_engine, monitor_name) super().__init__(event_engine, monitor_name)
class TradeMonitor(BasicMonitor): class TradeMonitor(BasicMonitor):
""" """
Monitor for trade data. Monitor for trade data.
@ -108,6 +108,7 @@ class TradeMonitor(BasicMonitor):
def __init__(self, event_engine=None, monitor_name='TradeMonitor'): def __init__(self, event_engine=None, monitor_name='TradeMonitor'):
super().__init__(event_engine, monitor_name) super().__init__(event_engine, monitor_name)
class OrderMonitor(BasicMonitor): class OrderMonitor(BasicMonitor):
""" """
Monitor for order data. Monitor for order data.
@ -135,6 +136,7 @@ class OrderMonitor(BasicMonitor):
def __init__(self, event_engine=None, monitor_name='OrderMonitor'): def __init__(self, event_engine=None, monitor_name='OrderMonitor'):
super().__init__(event_engine, monitor_name) super().__init__(event_engine, monitor_name)
class PositionMonitor(BasicMonitor): class PositionMonitor(BasicMonitor):
""" """
Monitor for position data. Monitor for position data.

View File

@ -16,6 +16,7 @@ assert os.path.isdir(logs_path)
# 记录pid得文件 # 记录pid得文件
pid_file = os.path.abspath(os.path.join(logs_path, 'gpid.txt')) pid_file = os.path.abspath(os.path.join(logs_path, 'gpid.txt'))
def _check_pid(pid): def _check_pid(pid):
""" """
检查pid是否与当前进程pid一致 检查pid是否与当前进程pid一致
@ -70,6 +71,7 @@ def update_pid():
# 执行检查 # 执行检查
if _check_status(): if _check_status():
import sys import sys
print(u'another service is already running...', file=sys.stderr) print(u'another service is already running...', file=sys.stderr)
exit(0) exit(0)

View File

@ -234,7 +234,7 @@ def get_folder_path(folder_name: str) -> Path:
folder_path = TEMP_DIR.joinpath(folder_name) folder_path = TEMP_DIR.joinpath(folder_name)
if not folder_path.exists(): if not folder_path.exists():
os.makedirs(str(folder_path)) os.makedirs(str(folder_path))
#folder_path.mkdir() # folder_path.mkdir()
return folder_path return folder_path