diff --git a/README.md b/README.md index 8ae7c5e7..0d8e7344 100644 --- a/README.md +++ b/README.md @@ -16,14 +16,14 @@ gitee 链接: https://gitee.com/vnpy2/vnpy + 直接使用,无需pip install easytrader; + 任然需要安装组件 pip install -r vnpy/api/easytrader/requirement.txt - vnpy.gateway.gj 国金证券的gateway - + 使用了tdx作为股票基础数据 - + 使用了天勤作为行情服务 + + 使用了t.d.x作为股票基础数据 + + 使用了天.勤.作为行情服务 + 使用了easytrader的remote_client作为接入. - prod.stock_qj 运行例子 + run_es_restful_server.py 放在A机器,安装国金全能客户端。 + run_main_gj01.py 放在B机器,运行vn_trader客户端 -15、天勤行情接入 +15、天.勤.行情接入 - vnpy.data.tq 定制downloder,扩展下载字段 - prod.jobs.refill_tq_future.ticks, 下载tick @@ -113,7 +113,7 @@ gitee 链接: https://gitee.com/vnpy2/vnpy - 提供指数行情订阅 - - 使用RabbitMQ指数源,或tdx单一数据源 + - 使用RabbitMQ指数源,或t.d.x单一数据源 - 提供自定义合约功能,实时提供其合成后的tick行情 - 增加天勤行情,实现上期所5档行情和指数行情 @@ -124,8 +124,7 @@ gitee 链接: https://gitee.com/vnpy2/vnpy 4、 增加App: tick_recorder, 直接异步写入csv文件 -3、 增加tdx 免费数据源,包括 - +3、 增加t.d.x 免费数据源,包括 - 提供主力合约/指数合约的信息获取 - 提供期货/股票数据bar 和分笔成交数据下载 diff --git a/vnpy/component/base.py b/vnpy/component/base.py index 1e20ac5e..c2e2dccf 100644 --- a/vnpy/component/base.py +++ b/vnpy/component/base.py @@ -26,9 +26,9 @@ class Area(Enum): # 上期所夜盘,9:00~10:15, 10:30~11:30, 13:30~15:00, 21:00 ~2:30 NIGHT_MARKET_SQ1 = {'AU': 0.05, 'AG': 1, 'SC': 0.1} # 上期所夜盘,9:00~10:15, 10:30~11:30, 13:30~15:00, 21:00 ~1:00 -NIGHT_MARKET_SQ2 = {'CU': 10, 'PB': 5, 'AL': 5, 'ZN': 5, 'WR': 1, 'NI': 10} +NIGHT_MARKET_SQ2 = {'CU': 10, 'PB': 5, 'AL': 5, 'ZN': 5, 'WR': 1, 'NI': 10, 'SS':5,'BC':10} # 上期所夜盘,9:00~10:15, 10:30~11:30, 13:30~15:00, 21:00 ~23:00 -NIGHT_MARKET_SQ3 = {'RU': 5, 'RB': 1, 'HC': 1, 'SP': 2, 'FU': 1, 'BU': 2, 'NR': 5, 'C': 1, 'CS': 1, 'LU':1} +NIGHT_MARKET_SQ3 = {'RU': 5, 'RB': 1, 'HC': 1, 'SP': 2, 'FU': 1, 'BU': 2, 'NR': 5, 'C': 1, 'CS': 1, 'LU':1,'PF':2} # 郑商所夜盘,9:00~10:15, 10:30~11:30, 13:30~15:00, 21:00 ~23:00 NIGHT_MARKET_ZZ = {'TA': 2, 'JR': 1, 'OI': 0, 'RO': 1, 'PM': 1, 'WH': 1, 'CF': 5, 'SR': 0, 'FG': 1, 'MA': 1, 'RS': 1, 'RM': 1, 'RI': 1, 'ZC': 0.2} @@ -42,7 +42,7 @@ MARKET_ZJ = {'IC': 0.2, 'IF': 0.2, 'IH': 0.2, 'T': 0.005, 'TF': 0.005, 'TS': 0.0 # 只有日盘得合约 MARKET_DAY_ONLY = {'IC': 0.2, 'IF': 0.2, 'IH': 0.2, 'T': 0.005, 'TF': 0.005, 'TS': 0.005, 'JD': 1, 'BB': 0.05, 'CS': 1, 'FB': 0.05, 'L': 5, 'V': 5, - 'JR': 1, 'LR': 1, 'PM': 1, 'RI': 1, 'RS': 1, 'SM': 2, 'WH': 1, 'AP': 1, 'CJ': 1, 'UR': 1} + 'JR': 1, 'LR': 1, 'PM': 1, 'RI': 1, 'RS': 1, 'SM': 2, 'WH': 1, 'AP': 1, 'CJ': 1, 'UR': 1,"LH":5,'PK':2} # 夜盘23:00收盘的合约 NIGHT_MARKET_23 = {**NIGHT_MARKET_DL, **NIGHT_MARKET_ZZ, **NIGHT_MARKET_SQ3} diff --git a/vnpy/component/cta_grid_trade.py b/vnpy/component/cta_grid_trade.py index 3bef54e2..78688da4 100644 --- a/vnpy/component/cta_grid_trade.py +++ b/vnpy/component/cta_grid_trade.py @@ -854,7 +854,7 @@ class CtaGridTrade(CtaComponent): except Exception: pass - def save(self): + def save(self, **kwargs): """ 保存网格至本地Json文件 2017/11/23 update: 保存时,空的列表也保存 @@ -865,7 +865,9 @@ class CtaGridTrade(CtaComponent): return # 更新开仓均价 - self.recount_avg_open_price() + if not kwargs.get('count_avg_price', True): + self.recount_avg_open_price() + grids_save_path = get_folder_path('data') # 确保json名字与策略一致 @@ -893,7 +895,7 @@ class CtaGridTrade(CtaComponent): self.write_log(u'GrideTrade保存文件{}完成'.format(grid_json_file)) - def load(self, direction, open_status_filter=[]): + def load(self, direction, open_status_filter=[], **kwargs): """ 加载本地Json至网格 :param direction: Direction.SHORT,做空网格;Direction.LONG,做多网格 @@ -950,7 +952,8 @@ class CtaGridTrade(CtaComponent): grids.append(grid) # 更新开仓均价 - self.recount_avg_open_price() + if not kwargs.get('count_avg_price',True): + self.recount_avg_open_price() return grids def change_strategy_name(self, old_name, new_name): diff --git a/vnpy/data/binance/binance_future_data.py b/vnpy/data/binance/binance_future_data.py index 525cad13..f37aa7f7 100644 --- a/vnpy/data/binance/binance_future_data.py +++ b/vnpy/data/binance/binance_future_data.py @@ -152,6 +152,43 @@ class BinanceFutureData(RestClient): return bars + def get_fund_rate(self, symbol=""): + + params = {} + if symbol: + params.update({"symbol": symbol}) + + # Get response from server + resp = self.request( + "GET", + "/fapi/v1/premiumIndex", + data={}, + params=params + ) + + # Break if request failed with other status code + if resp.status_code // 100 != 2: + msg = f"获取资费失败,状态码:{resp.status_code},信息:{resp.text}" + self.write_log(msg) + return {} if symbol else [] + else: + datas = resp.json() + if not datas: + msg = f"获取资费为空" + self.write_log(msg) + return {} if symbol else [] + + if isinstance(datas, list): + for d in datas: + for k in list(d.keys()): + if k in ['nextFundingTime', 'time']: + d.update({k: datetime.fromtimestamp(d.get(k) / 1000).strftime('%Y-%m-%d %H:%M:%S')}) + elif isinstance(datas, dict): + for k in list(datas.keys()): + if k in ['nextFundingTime', 'time']: + datas.update({k: datetime.fromtimestamp(datas.get(k) / 1000).strftime('%Y-%m-%d %H:%M:%S')}) + return datas + def export_to(self, bars, file_name): """导出bar到文件""" if len(bars) == 0: @@ -201,7 +238,7 @@ class BinanceFutureData(RestClient): "name": name, "price_tick": pricetick, "symbol_size": 20, - "margin_rate": round(float(d['requiredMarginPercent']) / 100, 5), + "margin_rate" : round(float(d['requiredMarginPercent']) / 100,5), "min_volume": min_volume, "product": Product.FUTURES.value, "commission_rate": 0.005 @@ -218,6 +255,7 @@ class BinanceFutureData(RestClient): contracts = load_json(f, auto_save=False) return contracts + def save_contracts(self): """保存合约配置""" contracts = self.get_contracts() diff --git a/vnpy/data/tdx/tdx_future_data.py b/vnpy/data/tdx/tdx_future_data.py index af977759..16363904 100644 --- a/vnpy/data/tdx/tdx_future_data.py +++ b/vnpy/data/tdx/tdx_future_data.py @@ -191,9 +191,12 @@ class TdxFutureData(object): if last_datetime_str: try: last_datetime = datetime.strptime(last_datetime_str, '%Y-%m-%d %H:%M:%S') - if (datetime.now() - last_datetime).total_seconds() > 60 * 60 * 2: + ip = self.best_ip.get('ip') + is_bad_ip = ip and ip in self.best_ip.get('exclude_ips',[]) + if (datetime.now() - last_datetime).total_seconds() > 60 * 60 * 2 or is_bad_ip : self.best_ip = {} - self.exclude_ips = [] + if not is_bad_ip: + self.exclude_ips = [] except Exception as ex: # noqa self.best_ip = {} else: diff --git a/vnpy/gateway/binancef/binancef_gateway.py b/vnpy/gateway/binancef/binancef_gateway.py index 1dfef594..60fa7ace 100644 --- a/vnpy/gateway/binancef/binancef_gateway.py +++ b/vnpy/gateway/binancef/binancef_gateway.py @@ -60,7 +60,8 @@ STATUS_BINANCEF2VT: Dict[str, Status] = { ORDERTYPE_VT2BINANCEF: Dict[OrderType, str] = { OrderType.LIMIT: "LIMIT", - OrderType.MARKET: "MARKET" + OrderType.MARKET: "MARKET", + OrderType.STOP: "STOP_MARKET" } ORDERTYPE_BINANCEF2VT: Dict[str, OrderType] = {v: k for k, v in ORDERTYPE_VT2BINANCEF.items()} @@ -172,7 +173,7 @@ class BinancefGateway(BaseGateway): self.status.update({'con': True}) self.count += 1 - if self.count < 2: + if self.count < 60: return self.count = 0 if len(self.query_functions) > 0: diff --git a/vnpy/gateway/binanceo/binanceo_gateway.py b/vnpy/gateway/binanceo/binanceo_gateway.py index c93b0924..653df400 100644 --- a/vnpy/gateway/binanceo/binanceo_gateway.py +++ b/vnpy/gateway/binanceo/binanceo_gateway.py @@ -198,7 +198,7 @@ class BinanceoGateway(BaseGateway): self.status.update({'con': True}) self.count += 1 - if self.count < 2: + if self.count < 60: return self.count = 0 if len(self.query_functions) > 0: diff --git a/vnpy/trader/utility.py b/vnpy/trader/utility.py index 99882aa7..83d4f47f 100644 --- a/vnpy/trader/utility.py +++ b/vnpy/trader/utility.py @@ -608,10 +608,10 @@ def save_images_to_excel(file_name, sheet_name, image_names): print(u'save_images_to_excel exception:{}'.format(str(ex)), traceback.format_exc(), file=sys.stderr) return False - def display_dual_axis(df, columns1, columns2=[], invert_yaxis1=False, invert_yaxis2=False, file_name=None, sheet_name=None, - image_name=None): + image_name=None, + label_column='index'): """ 显示(保存)双Y轴的走势图 :param df: DataFrame @@ -622,6 +622,7 @@ def display_dual_axis(df, columns1, columns2=[], invert_yaxis1=False, invert_yax :param file_name: 保存的excel 文件名称 :param sheet_name: excel 的sheet :param image_name: 保存的image 文件名 + :param label_cloumn: 显示在x轴的label所在字段,例如 df的index,或者 'datetime' 颜色色系:https://www.osgeo.cn/matplotlib/tutorials/colors/colormaps.html :return: """ @@ -648,7 +649,8 @@ def display_dual_axis(df, columns1, columns2=[], invert_yaxis1=False, invert_yax # 修改x轴得label为时间 xt = ax1.get_xticks() - xt2 = [df.index[int(i)] for i in xt[1:-2]] + label_values = df.index.values if label_column == 'index' else df[label_column].values + xt2 = [label_values[int(i)] for i in xt[1:-2]] xt2.insert(0, '') xt2.append('') ax1.set_xticklabels(xt2)