[一般更新] Flask8检查代码,套利模板,股票下载更新,天勤更新

This commit is contained in:
msincenselee 2020-10-10 14:14:53 +08:00
parent 74d156b3ae
commit b32ca3b9d5
30 changed files with 382 additions and 323 deletions

View File

@ -20,7 +20,7 @@ import baostock as bs
from vnpy.trader.constant import Exchange from vnpy.trader.constant import Exchange
from vnpy.data.tdx.tdx_common import get_tdx_market_code from vnpy.data.tdx.tdx_common import get_tdx_market_code
from vnpy.trader.utility import load_json, get_csv_last_dt, extract_vt_symbol from vnpy.trader.utility import load_json, get_csv_last_dt, extract_vt_symbol
from vnpy.data.stock.stock_base import get_stock_base from vnpy.data.stock.stock_base import update_stock_base, get_stock_base
# 保存的1分钟指数 bar目录 # 保存的1分钟指数 bar目录
bar_data_folder = os.path.abspath(os.path.join(vnpy_root, 'bar_data')) bar_data_folder = os.path.abspath(os.path.join(vnpy_root, 'bar_data'))
@ -34,6 +34,9 @@ if __name__ == "__main__":
if login_msg.error_code != '0': if login_msg.error_code != '0':
print(f'证券宝登录错误代码:{login_msg.error_code}, 错误信息:{login_msg.error_msg}') print(f'证券宝登录错误代码:{login_msg.error_code}, 错误信息:{login_msg.error_msg}')
print('更新股票基本信息')
update_stock_base()
symbol_dict = get_stock_base() symbol_dict = get_stock_base()
if len(sys.argv) >= 2 and sys.argv[1].lower() == 'all': if len(sys.argv) >= 2 and sys.argv[1].lower() == 'all':
stock_list = list(symbol_dict.keys()) stock_list = list(symbol_dict.keys())
@ -43,7 +46,6 @@ if __name__ == "__main__":
stock_list = load_json('stock_list.json') stock_list = load_json('stock_list.json')
print('读取本地stock_list.json文件{}'.format(len(stock_list))) print('读取本地stock_list.json文件{}'.format(len(stock_list)))
day_fields = "date,code,open,high,low,close,preclose,volume,amount,adjustflag,turn,tradestatus,pctChg,isST" day_fields = "date,code,open,high,low,close,preclose,volume,amount,adjustflag,turn,tradestatus,pctChg,isST"
min_fields = "date,time,code,open,high,low,close,volume,amount,adjustflag" min_fields = "date,time,code,open,high,low,close,volume,amount,adjustflag"
@ -74,7 +76,10 @@ if __name__ == "__main__":
exchange_name = '深交所' exchange_name = '深交所'
exchange_code = 'sz' exchange_code = 'sz'
symbol_info = symbol_dict.get(vt_symbol) symbol_info = symbol_dict.get(vt_symbol,None)
if symbol_info is None:
print(f'找不到{vt_symbol}得配置信息', file=sys.stderr)
continue
if symbol_info['类型'] == '指数': if symbol_info['类型'] == '指数':
continue continue
stock_name = symbol_info.get('name') stock_name = symbol_info.get('name')

View File

@ -1,4 +1,4 @@
six==1.13.0 six
PyQt5 PyQt5
pyqtgraph pyqtgraph
dataclasses; python_version<="3.6" dataclasses; python_version<="3.6"
@ -8,7 +8,7 @@ websocket-client
peewee peewee
mongoengine mongoengine
numpy numpy
pandas==0.25.2 pandas
matplotlib matplotlib
seaborn seaborn
futu-api futu-api

View File

@ -1945,7 +1945,7 @@ class BackTestingEngine(object):
self.daily_max_drawdown_rate = drawdown_rate self.daily_max_drawdown_rate = drawdown_rate
self.max_drawdown_rate_time = data['date'] self.max_drawdown_rate_time = data['date']
msg = u'{}: net={}, capital={} max={} margin={} commission={} pos: {}' \ msg = u'{}: net={}, capital={} max={} holding_profit={} commission={} pos: {}' \
.format(data['date'], .format(data['date'],
data['net'], c, m, data['net'], c, m,
today_holding_profit, today_holding_profit,

View File

@ -11,6 +11,7 @@ import sys
import os import os
import gc import gc
import pandas as pd import pandas as pd
import numpy as np
import traceback import traceback
import random import random
import bz2 import bz2
@ -425,7 +426,10 @@ class PortfolioTestingEngine(BackTestingEngine):
last_price=tick_data['price'], last_price=tick_data['price'],
volume=tick_data['volume'] volume=tick_data['volume']
) )
if not isinstance(tick.last_price,float):
continue
if np.isnan(tick.last_price):
continue
self.new_tick(tick) self.new_tick(tick)
# 结束一个交易日后,更新每日净值 # 结束一个交易日后,更新每日净值

View File

@ -11,6 +11,7 @@ import sys
import os import os
import gc import gc
import pandas as pd import pandas as pd
import numpy as np
import traceback import traceback
import bz2 import bz2
@ -426,6 +427,9 @@ class SpreadTestingEngine(BackTestingEngine):
bid_volume_1=int(tick_data['bid_volume_1']) bid_volume_1=int(tick_data['bid_volume_1'])
) )
if np.isnan(tick.ask_price_1) or np.isnan(tick.bid_price_1):
continue
self.new_tick(tick) self.new_tick(tick)
# 结束一个交易日后,更新每日净值 # 结束一个交易日后,更新每日净值

View File

@ -63,6 +63,12 @@ class CtaSpreadTemplate(CtaTemplate):
self.klines = {} # K线组件字典: kline_name: kline self.klines = {} # K线组件字典: kline_name: kline
self.cur_datetime = None # 当前Tick时间 self.cur_datetime = None # 当前Tick时间
self.cur_mi_tick = None # 最新的主力合约tick( vt_symbol)
self.cur_99_tick = None # 最新得指数合约tick( idx_symbol)
self.cur_mi_price = None # 当前价(主力合约 vt_symbol)
self.cur_99_price = None # 当前价tick时根据tick更新onBar回测时根据bar.close更新)
self.cur_act_tick = None # 最新的主动腿合约tick( act_vt_symbol) self.cur_act_tick = None # 最新的主动腿合约tick( act_vt_symbol)
self.cur_pas_tick = None # 最新得被动腿合约tick( pas_vt_symbol) self.cur_pas_tick = None # 最新得被动腿合约tick( pas_vt_symbol)
self.cur_spd_tick = None # 价差tick self.cur_spd_tick = None # 价差tick
@ -124,7 +130,6 @@ class CtaSpreadTemplate(CtaTemplate):
self.write_log(u'保存k线缓存数据') self.write_log(u'保存k线缓存数据')
self.save_klines_to_cache() self.save_klines_to_cache()
def save_klines_to_cache(self, kline_names: list = []): def save_klines_to_cache(self, kline_names: list = []):
""" """
保存K线数据到缓存 保存K线数据到缓存
@ -748,8 +753,8 @@ class CtaSpreadTemplate(CtaTemplate):
grid.order_ids.remove(order.vt_orderid) grid.order_ids.remove(order.vt_orderid)
# 网格的所有委托单已经执行完毕 # 网格的所有委托单已经执行完毕
if len(grid.order_ids) == 0: #if len(grid.order_ids) == 0:
grid.order_status = False # grid.order_status = False
self.gt.save() self.gt.save()
self.write_log(u'网格信息更新:{}'.format(grid.__dict__)) self.write_log(u'网格信息更新:{}'.format(grid.__dict__))
@ -776,7 +781,7 @@ class CtaSpreadTemplate(CtaTemplate):
self.write_log(f'{order_vt_symbol}涨停不做buy') self.write_log(f'{order_vt_symbol}涨停不做buy')
return return
# 发送委托 # FAK发送委托追单
vt_orderids = self.buy(price=buy_price, vt_orderids = self.buy(price=buy_price,
volume=order_volume, volume=order_volume,
vt_symbol=order_vt_symbol, vt_symbol=order_vt_symbol,
@ -855,8 +860,8 @@ class CtaSpreadTemplate(CtaTemplate):
self.write_log(f'移除grid中order_ids:{order.vt_orderid}') self.write_log(f'移除grid中order_ids:{order.vt_orderid}')
grid.order_ids.remove(order.vt_orderid) grid.order_ids.remove(order.vt_orderid)
if not grid.order_ids: #if not grid.order_ids:
grid.order_status = False # grid.order_status = False
self.gt.save() self.gt.save()
self.active_orders.update({order.vt_orderid: old_order}) self.active_orders.update({order.vt_orderid: old_order})
@ -872,7 +877,7 @@ class CtaSpreadTemplate(CtaTemplate):
return return
if not self.trading: if not self.trading:
self.write_error(u'当前不允许交易') self.write_error(f'{self.cur_datetime} 当前不允许交易')
return return
# 直接更新“未完成委托单”更新volume,Retry次数 # 直接更新“未完成委托单”更新volume,Retry次数
@ -906,8 +911,8 @@ class CtaSpreadTemplate(CtaTemplate):
if order.vt_orderid in grid.order_ids: if order.vt_orderid in grid.order_ids:
self.write_log(f'移除grid中order_ids:{order.vt_orderid}') self.write_log(f'移除grid中order_ids:{order.vt_orderid}')
grid.order_ids.remove(order.vt_orderid) grid.order_ids.remove(order.vt_orderid)
if not grid.order_ids: #if not grid.order_ids:
grid.order_status = False # grid.order_status = False
self.gt.save() self.gt.save()
self.write_log(u'更新网格=>{}'.format(grid.__dict__)) self.write_log(u'更新网格=>{}'.format(grid.__dict__))
@ -1001,8 +1006,8 @@ class CtaSpreadTemplate(CtaTemplate):
if order.vt_orderid in grid.order_ids: if order.vt_orderid in grid.order_ids:
self.write_log(f'移除grid中order_ids:{order.vt_orderid}') self.write_log(f'移除grid中order_ids:{order.vt_orderid}')
grid.order_ids.remove(order.vt_orderid) grid.order_ids.remove(order.vt_orderid)
if len(grid.order_ids) == 0: #if len(grid.order_ids) == 0:
grid.order_status = False # grid.order_status = False
self.gt.save() self.gt.save()
self.active_orders.update({order.vt_orderid: old_order}) self.active_orders.update({order.vt_orderid: old_order})
@ -1047,15 +1052,17 @@ class CtaSpreadTemplate(CtaTemplate):
self.active_orders.update({vt_orderid: order_info}) self.active_orders.update({vt_orderid: order_info})
ret = self.cancel_order(str(vt_orderid)) ret = self.cancel_order(str(vt_orderid))
if not ret: if not ret:
self.write_log(u'撤单失败,更新状态为撤单成功') self.write_log(f'{vt_orderid}撤单失败,更新状态为撤单成功')
order_info.update({'status': Status.CANCELLED}) order_info.update({'status': Status.CANCELLED})
self.active_orders.update({vt_orderid: order_info}) self.active_orders.update({vt_orderid: order_info})
else: else:
self.write_log(f'{vt_orderid}撤单成功')
if order_grid: if order_grid:
if vt_orderid in order_grid.order_ids: if vt_orderid in order_grid.order_ids:
self.write_log(f'{vt_orderid}存在网格委托队列{order_grid.order_ids}中,移除')
order_grid.order_ids.remove(vt_orderid) order_grid.order_ids.remove(vt_orderid)
if len(order_grid.order_ids) == 0: #if len(order_grid.order_ids) == 0:
order_grid.order_status = False # order_grid.order_status = False
continue continue
# 处理状态为‘撤销’的委托单 # 处理状态为‘撤销’的委托单
@ -1234,10 +1241,10 @@ class CtaSpreadTemplate(CtaTemplate):
self.write_log(u'停止状态,不开仓') self.write_log(u'停止状态,不开仓')
return [] return []
if not self.allow_trading_open: if not self.allow_trading_open:
self.write_log(u'不允许开仓') self.write_log(f'{self.cur_datetime}不允许开仓')
return [] return []
if self.force_trading_close: if self.force_trading_close:
self.write_log(u'强制平仓日,不开仓') self.write_log(f'{self.cur_datetime}强制平仓日,不开仓')
return [] return []
# 检查流动性缺失 # 检查流动性缺失
if not self.check_liquidity( direction=Direction.SHORT, if not self.check_liquidity( direction=Direction.SHORT,
@ -1266,7 +1273,7 @@ class CtaSpreadTemplate(CtaTemplate):
f'委托价:{self.cur_act_tick.bid_price_1}') f'委托价:{self.cur_act_tick.bid_price_1}')
return [] return []
# 开多被动腿 # 开多被动腿FAK或者限价单
pas_vt_orderids = self.buy(vt_symbol=self.pas_vt_symbol, pas_vt_orderids = self.buy(vt_symbol=self.pas_vt_symbol,
lock=self.pas_exchange==Exchange.CFFEX, lock=self.pas_exchange==Exchange.CFFEX,
price=self.cur_pas_tick.ask_price_1, price=self.cur_pas_tick.ask_price_1,
@ -1303,10 +1310,10 @@ class CtaSpreadTemplate(CtaTemplate):
self.write_log(u'停止状态,不开仓') self.write_log(u'停止状态,不开仓')
return [] return []
if not self.allow_trading_open: if not self.allow_trading_open:
self.write_log(u'不允许开仓') self.write_log(f'{self.cur_datetime}不允许开仓')
return [] return []
if self.force_trading_close: if self.force_trading_close:
self.write_log(u'强制平仓日,不开仓') self.write_log(f'{self.cur_datetime}强制平仓日,不开仓')
return [] return []
# 检查流动性缺失 # 检查流动性缺失
if not self.check_liquidity( if not self.check_liquidity(
@ -1324,7 +1331,7 @@ class CtaSpreadTemplate(CtaTemplate):
self.write_log(u'价差{}不满足:{}'.format(self.cur_spd_tick.bid_price_1, grid.open_price)) self.write_log(u'价差{}不满足:{}'.format(self.cur_spd_tick.bid_price_1, grid.open_price))
return [] return []
# 开多主动腿 # 开多主动腿FAK 或者限价单)
act_vt_orderids = self.buy(vt_symbol=self.act_vt_symbol, act_vt_orderids = self.buy(vt_symbol=self.act_vt_symbol,
lock=self.act_exchange==Exchange.CFFEX, lock=self.act_exchange==Exchange.CFFEX,
price=self.cur_act_tick.ask_price_1, price=self.cur_act_tick.ask_price_1,

View File

@ -300,6 +300,7 @@ class StrategyManager(QtWidgets.QFrame):
tns_csv = os.path.abspath(os.path.join(self.cta_engine.get_data_path(), f'{self.strategy_name}_tns.csv')) tns_csv = os.path.abspath(os.path.join(self.cta_engine.get_data_path(), f'{self.strategy_name}_tns.csv'))
ui_snapshot.show(snapshot_file="", d=snapshot, trade_file=trade_csv, tns_file=tns_csv) ui_snapshot.show(snapshot_file="", d=snapshot, trade_file=trade_csv, tns_file=tns_csv)
class DataMonitor(QtWidgets.QTableWidget): class DataMonitor(QtWidgets.QTableWidget):
""" """
Table monitor for parameters and variables. Table monitor for parameters and variables.
@ -477,7 +478,7 @@ class SettingEditor(QtWidgets.QDialog):
try: try:
value = type_(value_text) value = type_(value_text)
except Exception as ex: except Exception as ex:
print(f'{name}数据类型转换未指定') print(f'{name}数据类型转换未指定:{str(ex)}')
if isnumber(value_text): if isnumber(value_text):
value = float(value_text) value = float(value_text)
elif value_text == 'None': elif value_text == 'None':
@ -489,6 +490,7 @@ class SettingEditor(QtWidgets.QDialog):
return setting return setting
def isnumber(aString): def isnumber(aString):
try: try:
float(aString) float(aString)

View File

@ -40,7 +40,6 @@ class RiskManager(QtWidgets.QDialog):
self.trade_hold_active_limit_spin = RiskManagerSpinBox() self.trade_hold_active_limit_spin = RiskManagerSpinBox()
self.trade_hold_percent_limit_spin = RiskManagerSpinBox() self.trade_hold_percent_limit_spin = RiskManagerSpinBox()
save_button = QtWidgets.QPushButton("保存") save_button = QtWidgets.QPushButton("保存")
save_button.clicked.connect(self.save_setting) save_button.clicked.connect(self.save_setting)

View File

@ -5,3 +5,5 @@ HEIGHT_LIST = [3, 5, 10, 'K3', 'K5', 'K10']
FUTURE_RENKO_DB_NAME = 'FutureRenko' FUTURE_RENKO_DB_NAME = 'FutureRenko'
STOCK_RENKO_DB_NAME = 'StockRenko' STOCK_RENKO_DB_NAME = 'StockRenko'
CRYPTO_RENKO_DB_NAME= 'CryptoRenko'

View File

@ -26,6 +26,17 @@ stock_type_map = {
} }
STOCK_BASE_FILE = 'stock_base.pkb2' STOCK_BASE_FILE = 'stock_base.pkb2'
# get_stock_base 返回数据格式
# vt_symbol: {
# 'exchange': 交易所代码
# 'code': 股票代码
# 'name': 中文名
# 'ipo_date': 上市日期
# 'out_date': 退市日期
# '类型': 股票,指数,其他
# 'type': stock_cn, index_cn,etf_cn,bond_cn,cb_cn
# 'status': '上市' '退市'
# }
def get_stock_base(): def get_stock_base():
""" 获取股票基础信息""" """ 获取股票基础信息"""

View File

@ -46,7 +46,6 @@ NUM_MINUTE_MAPPING['1day'] = 60 * 5.5 # 股票收盘时间是1500
# 常量 # 常量
QSIZE = 800 QSIZE = 800
# 通达信 <=> 交易所代码 映射 # 通达信 <=> 交易所代码 映射
TDX_VN_STOCK_MARKET_MAP = { TDX_VN_STOCK_MARKET_MAP = {
TDXParams.MARKET_SH: Exchange.SSE, # 1: 上交所 TDXParams.MARKET_SH: Exchange.SSE, # 1: 上交所
@ -531,8 +530,10 @@ class TdxStockData(object):
self.connect() self.connect()
data = pd.concat( data = pd.concat(
[pd.concat([self.api.to_df(self.api.get_security_list(j, i * 1000)).assign(sse='sz' if j == 0 else 'sh').set_index( [pd.concat(
['code', 'sse'], drop=False) for i in range(int(self.api.get_security_count(j) / 1000) + 1)], axis=0) for j [self.api.to_df(self.api.get_security_list(j, i * 1000)).assign(sse='sz' if j == 0 else 'sh').set_index(
['code', 'sse'], drop=False) for i in range(int(self.api.get_security_count(j) / 1000) + 1)],
axis=0) for j
in range(2)], axis=0) in range(2)], axis=0)
sz = data.query('sse=="sz"') sz = data.query('sse=="sz"')
sh = data.query('sse=="sh"') sh = data.query('sse=="sh"')
@ -575,7 +576,8 @@ class TdxStockData(object):
def get_stock_quotes_by_type(self, stock_type): def get_stock_quotes_by_type(self, stock_type):
"""根据股票代码类型,获取其最新行情""" """根据股票代码类型,获取其最新行情"""
stock_list = [(stock.get('market_id'), stock.get('code')) for stock in self.symbol_dict.values() if stock.get('stock_type') == stock_type] stock_list = [(stock.get('market_id'), stock.get('code')) for stock in self.symbol_dict.values() if
stock.get('stock_type') == stock_type]
num_per_count = 60 num_per_count = 60
results = [] results = []

View File

@ -18,12 +18,12 @@ t2 = FakeStrategy()
api_01 = TdxFutureData(strategy=t1) api_01 = TdxFutureData(strategy=t1)
# 获取所有市场信息 # 获取所有市场信息
markets = api_01.get_markets() #markets = api_01.get_markets()
str_markets = json.dumps(markets, indent=1, ensure_ascii=False) #str_markets = json.dumps(markets, indent=1, ensure_ascii=False)
print(u'{}'.format(str_markets)) #print(u'{}'.format(str_markets))
# 获取所有的期货合约明细 # 获取所有的期货合约明细
api_01.qry_instrument() #api_01.qry_instrument()
# 获取某个合约得最新价 # 获取某个合约得最新价
#price = api_01.get_price('rb2010') #price = api_01.get_price('rb2010')
@ -64,8 +64,8 @@ corr_rate = round(abs(corr.iloc[0, 1]) * 100, 2)
# api_01.get_bars('IF99', period='1min', callback=t1.display_bar, bar_freq=1) # api_01.get_bars('IF99', period='1min', callback=t1.display_bar, bar_freq=1)
# 获取bar只返回 list[dict] # 获取bar只返回 list[dict]
"""
result, bars = api_01.get_bars('IF99', period='1min', return_bar=False) result, bars = api_01.get_bars('SA2101', period='1min', return_bar=False)
if result: if result:
print('前十根bar') print('前十根bar')
for bar in bars[0:10]: for bar in bars[0:10]:
@ -73,15 +73,15 @@ if result:
print('后十根bar') print('后十根bar')
for bar in bars[-10:]: for bar in bars[-10:]:
print(bar) print(bar)
"""
# result,datas = api_01.get_transaction_data(symbol='ni1905') # result,datas = api_01.get_transaction_data(symbol='ni1905')
# api_02 = TdxFutureData(t2) # api_02 = TdxFutureData(t2)
# api_02.get_bars('IF99', period='1min', callback=t1.display_bar) # api_02.get_bars('IF99', period='1min', callback=t1.display_bar)
# 获取当前交易日分时数据 # 获取当前交易日分时数据
ret,result = api_01.get_transaction_data('NI99') #ret,result = api_01.get_transaction_data('NI99')
for r in result[0:10] + result[-10:]: #for r in result[0:10] + result[-10:]:
print(r) # print(r)
# 获取历史分时数据 # 获取历史分时数据
# ret, result = api_01.get_history_transaction_data('RB99', '20190109') # ret, result = api_01.get_history_transaction_data('RB99', '20190109')

View File

@ -74,11 +74,13 @@ class DataDownloader:
if isinstance(start_dt, datetime): if isinstance(start_dt, datetime):
self._start_dt_nano = int(start_dt.timestamp() * 1e9) self._start_dt_nano = int(start_dt.timestamp() * 1e9)
else: else:
self._start_dt_nano = _get_trading_day_start_time(int(datetime(start_dt.year, start_dt.month, start_dt.day).timestamp()) * 1000000000) self._start_dt_nano = _get_trading_day_start_time(
int(datetime(start_dt.year, start_dt.month, start_dt.day).timestamp()) * 1000000000)
if isinstance(end_dt, datetime): if isinstance(end_dt, datetime):
self._end_dt_nano = int(end_dt.timestamp() * 1e9) self._end_dt_nano = int(end_dt.timestamp() * 1e9)
else: else:
self._end_dt_nano = _get_trading_day_end_time(int(datetime(end_dt.year, end_dt.month, end_dt.day).timestamp()) * 1000000000) self._end_dt_nano = _get_trading_day_end_time(
int(datetime(end_dt.year, end_dt.month, end_dt.day).timestamp()) * 1000000000)
self._current_dt_nano = self._start_dt_nano self._current_dt_nano = self._start_dt_nano
self._symbol_list = symbol_list if isinstance(symbol_list, list) else [symbol_list] self._symbol_list = symbol_list if isinstance(symbol_list, list) else [symbol_list]
# 检查合约代码是否存在 # 检查合约代码是否存在

View File

@ -37,6 +37,7 @@ tick_csv_header = [
"bid_price5", "bid_volume5", "ask_price5", "ask_volume5" "bid_price5", "bid_volume5", "ask_price5", "ask_volume5"
] ]
@lru_cache(maxsize=9999) @lru_cache(maxsize=9999)
def to_vt_symbol(tq_symbol: str) -> str: def to_vt_symbol(tq_symbol: str) -> str:
"""""" """"""
@ -235,7 +236,6 @@ class TqFutureData():
return bars return bars
def get_ticks(self, vt_symbol: str, start_date: datetime, end_date: datetime = None): def get_ticks(self, vt_symbol: str, start_date: datetime, end_date: datetime = None):
"""获取历史tick""" """获取历史tick"""
@ -352,7 +352,3 @@ if __name__ == '__main__':
bars = tqsdk.get_bars(vt_symbol='ni2011.SHFE') bars = tqsdk.get_bars(vt_symbol='ni2011.SHFE')
print(bars[0]) print(bars[0])
print(bars[-1]) print(bars[-1])

View File

@ -180,6 +180,7 @@ TQ2VT_TYPE = {
"OPTION": Product.OPTION, "OPTION": Product.OPTION,
} }
@lru_cache(maxsize=9999) @lru_cache(maxsize=9999)
def vt_to_tq_symbol(symbol: str, exchange: Exchange) -> str: def vt_to_tq_symbol(symbol: str, exchange: Exchange) -> str:
""" """
@ -544,6 +545,7 @@ class CtpGateway(BaseGateway):
tick = copy(tick) tick = copy(tick)
combiner.on_tick(tick) combiner.on_tick(tick)
class CtpMdApi(MdApi): class CtpMdApi(MdApi):
"""""" """"""
@ -984,8 +986,11 @@ class CtpTdApi(TdApi):
account.available = round(float(data["Available"]), 7) account.available = round(float(data["Available"]), 7)
account.commission = round(float(data['Commission']), 7) account.commission = round(float(data['Commission']), 7)
account.margin = round(float(data['CurrMargin']), 7) account.margin = round(float(data['CurrMargin']), 7)
account.close_profit = round(float(data['CloseProfit']), 7) account.close_profit = round(float(data['CloseProfit']), 7) + round(
account.holding_profit = round(float(data['PositionProfit']), 7) float(data.get("SpecProductCloseProfit", 0)), 7)
account.holding_profit = round(float(data['PositionProfit']), 7) + round(
float(data.get("SpecProductPositionProfit", 0)), 7) + round(
float(data.get("SpecProductPositionProfitByAlg", 0)), 7)
account.trading_day = str(data['TradingDay']) account.trading_day = str(data['TradingDay'])
if '-' not in account.trading_day and len(account.trading_day) == 8: if '-' not in account.trading_day and len(account.trading_day) == 8:
account.trading_day = '-'.join( account.trading_day = '-'.join(
@ -1805,7 +1810,6 @@ class SubMdApi():
d.update({'open_interest': d.pop('tradingDay', get_trading_date())}) d.update({'open_interest': d.pop('tradingDay', get_trading_date())})
# 常规行情 # 常规行情
d.update({'open_price': d.pop('openPrice', 0)}) # 今日开盘价 d.update({'open_price': d.pop('openPrice', 0)}) # 今日开盘价
d.update({'high_price': d.pop('highPrice', 0)}) # 今日最高价 d.update({'high_price': d.pop('highPrice', 0)}) # 今日最高价

View File

@ -17,6 +17,11 @@ from functools import lru_cache
from collections import OrderedDict from collections import OrderedDict
from multiprocessing.dummy import Pool from multiprocessing.dummy import Pool
from threading import Thread from threading import Thread
from pytdx.hq import TdxHq_API
from pytdx.config.hosts import hq_hosts
from pytdx.params import TDXParams
from vnpy.event import EventEngine from vnpy.event import EventEngine
from vnpy.trader.event import EVENT_TIMER from vnpy.trader.event import EVENT_TIMER
from vnpy.trader.constant import ( from vnpy.trader.constant import (
@ -45,6 +50,9 @@ from vnpy.trader.object import (
from vnpy.trader.utility import get_folder_path, print_dict, extract_vt_symbol, get_stock_exchange, append_data from vnpy.trader.utility import get_folder_path, print_dict, extract_vt_symbol, get_stock_exchange, append_data
from vnpy.data.tdx.tdx_common import get_stock_type_sz, get_stock_type_sh from vnpy.data.tdx.tdx_common import get_stock_type_sz, get_stock_type_sh
# 通达信股票行情
from vnpy.data.tdx.tdx_common import get_cache_config, get_tdx_market_code
# 代码 <=> 中文名称 # 代码 <=> 中文名称
symbol_name_map: Dict[str, str] = {} symbol_name_map: Dict[str, str] = {}
# 代码 <=> 交易所 # 代码 <=> 交易所
@ -303,11 +311,6 @@ STATUS_PB2VT: Dict[str, Status] = {
} }
STOCK_CONFIG_FILE = 'tdx_stock_config.pkb2' STOCK_CONFIG_FILE = 'tdx_stock_config.pkb2'
from pytdx.hq import TdxHq_API
# 通达信股票行情
from vnpy.data.tdx.tdx_common import get_cache_config, get_tdx_market_code
from pytdx.config.hosts import hq_hosts
from pytdx.params import TDXParams
class PbGateway(BaseGateway): class PbGateway(BaseGateway):
@ -1654,7 +1657,8 @@ class PbTdApi(object):
order.status = Status.REJECTED order.status = Status.REJECTED
self.gateway.write_log(f'dbf批量下单委托被拒:{order.__dict__}') self.gateway.write_log(f'dbf批量下单委托被拒:{order.__dict__}')
self.gateway.order_manager.on_order(order) self.gateway.order_manager.on_order(order)
self.gateway.write_error(msg=f'{order.direction.value},{order.vt_symbol},{err_msg}', error={"ErrorID": err_id, "ErrorMsg": "委托失败"}) self.gateway.write_error(msg=f'{order.direction.value},{order.vt_symbol},{err_msg}',
error={"ErrorID": err_id, "ErrorMsg": "委托失败"})
if sys_orderid != '0': if sys_orderid != '0':
self.gateway.order_manager.update_orderid_map(local_orderid=local_orderid, self.gateway.order_manager.update_orderid_map(local_orderid=local_orderid,
@ -1933,7 +1937,6 @@ class PbTdApi(object):
'{}{}.dbf'.format(PB_FILE_NAMES.get('cancel_order'), '{}{}.dbf'.format(PB_FILE_NAMES.get('cancel_order'),
self.trading_date))) self.trading_date)))
# 打开dbf文件=》table # 打开dbf文件=》table
table = dbf.Table(dbf_file) table = dbf.Table(dbf_file)
# 读取、写入模式 # 读取、写入模式
@ -2069,7 +2072,7 @@ class TqMdApi():
return return
try: try:
from tqsdk import TqApi from tqsdk import TqApi
self.api = TqApi(_stock=True) self.api = TqApi(_stock=True, url="wss://u.shinnytech.com/t/nfmd/front/mobile")
except Exception as e: except Exception as e:
self.gateway.write_log(f'天勤股票行情API接入异常:'.format(str(e))) self.gateway.write_log(f'天勤股票行情API接入异常:'.format(str(e)))
self.gateway.write_log(traceback.format_exc()) self.gateway.write_log(traceback.format_exc())
@ -2203,4 +2206,3 @@ class TqMdApi():
self.update_thread.join() self.update_thread.join()
except Exception as e: except Exception as e:
self.gateway.write_log('退出天勤行情api异常:{}'.format(str(e))) self.gateway.write_log('退出天勤行情api异常:{}'.format(str(e)))

View File

@ -175,6 +175,7 @@ TQ2VT_TYPE = {
"OPTION": Product.OPTION, "OPTION": Product.OPTION,
} }
@lru_cache(maxsize=9999) @lru_cache(maxsize=9999)
def vt_to_tq_symbol(symbol: str, exchange: Exchange) -> str: def vt_to_tq_symbol(symbol: str, exchange: Exchange) -> str:
""" """
@ -537,6 +538,7 @@ class RohonGateway(BaseGateway):
tick = copy(tick) tick = copy(tick)
combiner.on_tick(tick) combiner.on_tick(tick)
class RohonMdApi(MdApi): class RohonMdApi(MdApi):
"""""" """"""
@ -1762,7 +1764,7 @@ class SubMdApi():
return d return d
symbol = d.get('symbol') symbol = d.get('symbol')
exchange = d.get('exchange') exchange = d.get('exchange')
vtSymbol = d.pop('vtSymbol', symbol) d.pop('vtSymbol', None)
if '.' not in symbol: if '.' not in symbol:
d.update({'vt_symbol': f'{symbol}.{exchange}'}) d.update({'vt_symbol': f'{symbol}.{exchange}'})
else: else:
@ -1776,7 +1778,6 @@ class SubMdApi():
d.update({'open_interest': d.pop('tradingDay', get_trading_date())}) d.update({'open_interest': d.pop('tradingDay', get_trading_date())})
# 常规行情 # 常规行情
d.update({'open_price': d.pop('openPrice', 0)}) # 今日开盘价 d.update({'open_price': d.pop('openPrice', 0)}) # 今日开盘价
d.update({'high_price': d.pop('highPrice', 0)}) # 今日最高价 d.update({'high_price': d.pop('highPrice', 0)}) # 今日最高价
@ -1960,7 +1961,7 @@ class TqMdApi():
def query_contracts(self) -> None: def query_contracts(self) -> None:
"""""" """"""
self.all_instruments = [ self.all_instruments = [
v for k, v in self.api._data["quotes"].items() if v["expired"] == False v for k, v in self.api._data["quotes"].items() if not v["expired"]
] ]
for contract in self.all_instruments: for contract in self.all_instruments:
if ( if (

View File

@ -71,7 +71,6 @@ from vnpy.trader.utility import (
) )
from vnpy.trader.event import EVENT_TIMER from vnpy.trader.event import EVENT_TIMER
STATUS_SOPT2VT = { STATUS_SOPT2VT = {
THOST_FTDC_OAS_Submitted: Status.SUBMITTING, THOST_FTDC_OAS_Submitted: Status.SUBMITTING,
THOST_FTDC_OAS_Accepted: Status.SUBMITTING, THOST_FTDC_OAS_Accepted: Status.SUBMITTING,
@ -127,6 +126,7 @@ symbol_name_map = {}
symbol_size_map = {} symbol_size_map = {}
option_name_map = {} option_name_map = {}
class SoptGateway(BaseGateway): class SoptGateway(BaseGateway):
""" """
VN Trader Gateway for SOPT . VN Trader Gateway for SOPT .
@ -306,7 +306,6 @@ class SoptGateway(BaseGateway):
self.query_functions = [self.query_account, self.query_position] self.query_functions = [self.query_account, self.query_position]
self.event_engine.register(EVENT_TIMER, self.process_timer_event) self.event_engine.register(EVENT_TIMER, self.process_timer_event)
def on_custom_tick(self, tick): def on_custom_tick(self, tick):
"""推送自定义合约行情""" """推送自定义合约行情"""
# 自定义合约行情 # 自定义合约行情
@ -408,6 +407,7 @@ class SoptMdApi(MdApi):
ask_price_1=data["AskPrice1"], ask_price_1=data["AskPrice1"],
bid_volume_1=data["BidVolume1"], bid_volume_1=data["BidVolume1"],
ask_volume_1=data["AskVolume1"], ask_volume_1=data["AskVolume1"],
trading_day=dt.strftime('%Y-%m-%d'),
gateway_name=self.gateway_name gateway_name=self.gateway_name
) )
@ -597,7 +597,8 @@ class SoptTdApi(TdApi):
) )
self.gateway.on_order(order) self.gateway.on_order(order)
self.gateway.write_error(f"交易委托失败:{symbol} {order.direction.value} {order.offset.value} {order.price}, {order.volume}", error) self.gateway.write_error(
f"交易委托失败:{symbol} {order.direction.value} {order.offset.value} {order.price}, {order.volume}", error)
def onRspOrderAction(self, data: dict, error: dict, reqid: int, last: bool): def onRspOrderAction(self, data: dict, error: dict, reqid: int, last: bool):
"""""" """"""
@ -682,16 +683,20 @@ class SoptTdApi(TdApi):
# 重新累计多头期权动态权益 # 重新累计多头期权动态权益
if position.direction == Direction.LONG: if position.direction == Direction.LONG:
if self.long_option_cost is None: if self.long_option_cost is None:
self.long_option_cost = position.cur_price * position.volume * symbol_size_map.get(position.symbol, 0) self.long_option_cost = position.cur_price * position.volume * symbol_size_map.get(
position.symbol, 0)
else: else:
self.long_option_cost += position.cur_price * position.volume * symbol_size_map.get(position.symbol, 0) self.long_option_cost += position.cur_price * position.volume * symbol_size_map.get(
position.symbol, 0)
# 重新累计空头期权动态权益 # 重新累计空头期权动态权益
if position.direction == Direction.SHORT: if position.direction == Direction.SHORT:
if self.short_option_cost is None: if self.short_option_cost is None:
self.short_option_cost = position.cur_price * position.volume * symbol_size_map.get(position.symbol, 0) self.short_option_cost = position.cur_price * position.volume * symbol_size_map.get(
position.symbol, 0)
else: else:
self.short_option_cost += position.cur_price * position.volume * symbol_size_map.get(position.symbol, 0) self.short_option_cost += position.cur_price * position.volume * symbol_size_map.get(
position.symbol, 0)
self.gateway.on_position(position) self.gateway.on_position(position)
@ -723,7 +728,8 @@ class SoptTdApi(TdApi):
account.commission = round(float(data['Commission']), 7) + round(float(data['SpecProductCommission']), 7) account.commission = round(float(data['Commission']), 7) + round(float(data['SpecProductCommission']), 7)
account.margin = round(float(data['CurrMargin']), 7) account.margin = round(float(data['CurrMargin']), 7)
account.close_profit = round(float(data['CloseProfit']), 7) + round(float(data['SpecProductCloseProfit']), 7) account.close_profit = round(float(data['CloseProfit']), 7) + round(float(data['SpecProductCloseProfit']), 7)
account.holding_profit = round(float(data['PositionProfit']), 7) + round(float(data['SpecProductPositionProfit']), 7) account.holding_profit = round(float(data['PositionProfit']), 7) + round(
float(data['SpecProductPositionProfit']), 7)
account.trading_day = str(data.get('TradingDay', datetime.now().strftime('%Y-%m-%d'))) account.trading_day = str(data.get('TradingDay', datetime.now().strftime('%Y-%m-%d')))
if '-' not in account.trading_day and len(account.trading_day) == 8: if '-' not in account.trading_day and len(account.trading_day) == 8:

View File

@ -128,12 +128,13 @@ symbol_name_map: Dict[str, str] = {}
# 代码 <=> 交易所 # 代码 <=> 交易所
symbol_exchange_map: Dict[str, Exchange] = {} symbol_exchange_map: Dict[str, Exchange] = {}
@lru_cache() @lru_cache()
def get_vt_symbol_name(vt_symbol): def get_vt_symbol_name(vt_symbol):
return symbol_name_map.get(vt_symbol, vt_symbol.split('.')[0]) return symbol_name_map.get(vt_symbol, vt_symbol.split('.')[0])
class XtpGateway(BaseGateway):
class XtpGateway(BaseGateway):
default_setting: Dict[str, Any] = { default_setting: Dict[str, Any] = {
"账号": "", "账号": "",
"密码": "", "密码": "",

View File

@ -165,6 +165,7 @@ class Interval(Enum):
WEEKLY = "w" WEEKLY = "w"
RENKO = 'renko' RENKO = 'renko'
class StockType(Enum): class StockType(Enum):
"""股票类型tdx""" """股票类型tdx"""
STOCK = 'stock_cn' # 股票 STOCK = 'stock_cn' # 股票

View File

@ -766,6 +766,7 @@ class OmsEngine(BaseEngine):
"""根据主动腿/被动腿symbol获取自定义套利对的symbol list""" """根据主动腿/被动腿symbol获取自定义套利对的symbol list"""
return self.symbol_spd_maping.get(symbol, []) return self.symbol_spd_maping.get(symbol, [])
class CustomContract(object): class CustomContract(object):
""" """
定制合约 定制合约

View File

@ -209,6 +209,7 @@ class TradeData(BaseData):
self.vt_tradeid = f"{self.gateway_name}.{self.tradeid}" self.vt_tradeid = f"{self.gateway_name}.{self.tradeid}"
self.vt_accountid = f"{self.gateway_name}.{self.accountid}" self.vt_accountid = f"{self.gateway_name}.{self.accountid}"
@dataclass @dataclass
class PositionData(BaseData): class PositionData(BaseData):
""" """
@ -238,6 +239,7 @@ class PositionData(BaseData):
if self.name == "": if self.name == "":
self.name = self.vt_symbol self.name = self.vt_symbol
@dataclass @dataclass
class AccountData(BaseData): class AccountData(BaseData):
""" """

View File

@ -9,7 +9,6 @@ from copy import copy
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets
from vnpy.event import Event, EventEngine from vnpy.event import Event, EventEngine
from ..constant import Direction, Exchange, Offset, OrderType from ..constant import Direction, Exchange, Offset, OrderType
from ..engine import MainEngine from ..engine import MainEngine

View File

@ -14,15 +14,16 @@ import requests
import sys import sys
import traceback import traceback
from datetime import datetime from datetime import datetime
from functools import wraps # from functools import wraps
from vnpy.trader.utility import print_dict from vnpy.trader.utility import print_dict
global wechat_lock global wechat_lock
wechat_lock = Lock() wechat_lock = Lock()
# 这里可以设置UIDS, 多个人可同时接收 # 这里可以设置UIDS, 多个人可同时接收
UIDS = ['UID_kZguGPBQPWn41Ni9FK4CgPts2KjU'] UIDS = ['UID_kZguGPBQPWn41Ni9FK4CgPts2Kjx']
APP_TOKEN = 'AT_aDuiQu41dmAQV2vUMXOaaTDrWyhKJN2z' APP_TOKEN = 'AT_aDuiQu41dmAQV2vUMXOaaTDrWyhKJN2x'
class wechat_thread(Thread): class wechat_thread(Thread):
@ -42,7 +43,7 @@ class wechat_thread(Thread):
self.topic_ids = topic_ids self.topic_ids = topic_ids
self.url = url self.url = url
self.lock = wechat_lock self.lock = wechat_lock
self.app_token = app_token if len(app_token) > 0 else APP_TOKEN self.app_token = app_token if app_token is not None and len(app_token) > 0 else APP_TOKEN
def run(self): def run(self):
if self.content is None or len(self.content) == 0: if self.content is None or len(self.content) == 0:
@ -61,7 +62,7 @@ class wechat_thread(Thread):
if not response.get('success', False): if not response.get('success', False):
print(response) print(response)
except Exception as e: except Exception as e:
print("{} wechat_thread sent failed! ex:{},trace:{}".format(datetime.now(), str(e), traceback.format_exc()), print("{} 微信发送异常 ex:{},trace:{}".format(datetime.now(), str(e), traceback.format_exc()),
file=sys.stderr) file=sys.stderr)
return return
@ -84,7 +85,8 @@ def send_wx_msg(*args, **kwargs):
try: try:
# 如果存在华富资产的微信模块,则使用 # 如果存在华富资产的微信模块,则使用
from vnpy.trader.util_huafu import sendWeChatMsg, WECHAT_URL,WECHAT_GROUP, WECHAT_LEVEL_INFO, WECHAT_MSG_TYPE_ALERT from vnpy.trader.util_huafu import sendWeChatMsg, WECHAT_URL, WECHAT_GROUP, WECHAT_LEVEL_INFO, \
WECHAT_MSG_TYPE_ALERT
target = kwargs.get('target', 'XXX') target = kwargs.get('target', 'XXX')
sendWeChatMsg(content=content, sendWeChatMsg(content=content,
target=WECHAT_GROUP.get(target), target=WECHAT_GROUP.get(target),
@ -93,6 +95,7 @@ def send_wx_msg(*args, **kwargs):
msg_type=kwargs.get('msg_type', WECHAT_MSG_TYPE_ALERT)) msg_type=kwargs.get('msg_type', WECHAT_MSG_TYPE_ALERT))
return return
except Exception as ex: except Exception as ex:
print(f'发送微信异常:{str(ex)}', file=sys.stderr)
pass pass
# dict => str, none str => str # dict => str, none str => str
@ -114,6 +117,7 @@ def send_wx_msg(*args, **kwargs):
# t.run() # t.run()
t.start() t.start()
if __name__ == '__main__': if __name__ == '__main__':
text = u'微信测试标题!!!!\n第二行' text = u'微信测试标题!!!!\n第二行'

View File

@ -163,6 +163,7 @@ def get_trading_date(dt: datetime = None):
else: else:
return dt.strftime('%Y-%m-%d') return dt.strftime('%Y-%m-%d')
def extract_vt_symbol(vt_symbol: str) -> Tuple[str, Exchange]: def extract_vt_symbol(vt_symbol: str) -> Tuple[str, Exchange]:
""" """
:return: (symbol, exchange) :return: (symbol, exchange)
@ -328,6 +329,7 @@ def get_digits(value: float) -> int:
else: else:
return 0 return 0
def print_dict(d: dict): def print_dict(d: dict):
"""返回dict的字符串类型""" """返回dict的字符串类型"""
return '\n'.join([f'{key}:{d[key]}' for key in sorted(d.keys())]) return '\n'.join([f'{key}:{d[key]}' for key in sorted(d.keys())])
@ -356,6 +358,7 @@ def get_csv_last_dt(file_name, dt_index=0, dt_format='%Y-%m-%d %H:%M:%S', line_l
return None return None
return None return None
def append_data(file_name: str, dict_data: dict, field_names: list = [], auto_header=True, encoding='utf8'): def append_data(file_name: str, dict_data: dict, field_names: list = [], auto_header=True, encoding='utf8'):
""" """
添加数据到csv文件中 添加数据到csv文件中
@ -669,6 +672,7 @@ def load_data_from_pkb2(pkb2_file_name):
data = pickle.load(f) data = pickle.load(f)
return data return data
def save_data_to_pkb2(data: Any, pkb2_file_name): def save_data_to_pkb2(data: Any, pkb2_file_name):
"""保存本地缓存的配置地址信息""" """保存本地缓存的配置地址信息"""
with bz2.BZ2File(pkb2_file_name, 'wb') as f: with bz2.BZ2File(pkb2_file_name, 'wb') as f: