vn.py官网
开源量化社区
Member
加入于:
帖子: 136
声望: 44

刚好有个同学问怎么实现IB历史数据获取,和策略回测和实盘交易。想着熟悉vnpy2.0操作,就用Jupyter Notebook都是跑了一边。VNPY2.0的整体架构设计很有扩展性,而且调用也比起v1.0先进清晰很多,引擎加载调用非常方便。

讲讲注意点:

  1. IB接口历史数据大多是要收费的订阅的,如果收费会有报错信息提示,这里找个免费的作为使用。另外vnpy是按照最大6个月历史数据设计的。
  2. 数据库定义有个小坑,我是用mongodb的,在第一次填写 trader/setting.py中密码写错了,后面在trader/setting.py改发现怎么也改不好;原来当第一次维护后,配置会写入.vntrader/vt_setting,之后系统只会去.vntrader/vt_setting读取。去改vt_setting,而不是trader/setting.py。
  3. 使用CtaStrategyApp支持加入新策略,系统会自动输出json保持策略信息;所以第二次运行代码时候,会提示已经有了,不是问题。
  4. 我在代码里面把回测和实盘放在一次,如果直接跑下来可能会报错,建议跑实盘时候先注释的回测。
  5. 使用script_engine订阅历史数据是是默认从rqdata获取,vnpy v2.07 IB接口已经提供历史数据获取,这里创建HistoryRequest用main_engine来获取,

为了方便贴出来,改成.py代码格式,直接跑也没有问题。

from vnpy.app.script_trader import init_cli_trading
from vnpy.app.script_trader.cli import process_log_event
from vnpy.gateway.ib import IbGateway
from time import sleep
from datetime import datetime
import pandas as pd
# 连接到服务器
setting = {
    "TWS地址": "127.0.0.1",
    "TWS端口": 7497,
    "客户号":8 #每个链接用一个独立的链接号,一个IBAPI支持32个来同时链接
}
engine = init_cli_trading([IbGateway]) #返回Script_engine 示例,并且给main_engine注册了gateway
engine.connect_gateway(setting, "IB") #链接

# 查询资金 - 自动
sleep(10)
print("***查询资金和持仓***")
print(engine.get_all_accounts(use_df = True))
# 查询持仓
print(engine.get_all_positions(use_df = True))

# 订阅行情
from vnpy.trader.constant import Exchange
from vnpy.trader.object import SubscribeRequest
# 从我测试直接用Script_engine有问题,IB的品种太多,get_all_contracts命令不行,需要指定具体后才可以,这里使用main_engine订阅
req1 = SubscribeRequest("12087792",Exchange.IDEALPRO) #创建行情订阅
engine.main_engine.subscribe(req1,"IB")


# 使用script_engine订阅历史数据是从rqdata获取,vnpy v2.07已经提供历史数据获取,这里创建HistoryRequest来获取,
# 查询如果没有endtime,默认当前。返回历史数据输出到数据库和csv文件
# 关于api更多信息可以参见 https://interactivebrokers.github.io/tws-api/historical_bars.html
print("***从IB读取历史数据, 返回历史数据输出到数据库和csv文件***")
from vnpy.trader.object import HistoryRequest
from vnpy.trader.object import Interval
start = datetime.strptime('20190901', "%Y%m%d")

historyreq = HistoryRequest(
    symbol="12087792",
    exchange=Exchange.IDEALPRO,
    start=start,
    interval=Interval.MINUTE
)
# # 读取历史数据,并把历史数据BarData放入数据库
bardatalist = engine.main_engine.query_history(historyreq,"IB")
from vnpy.trader.database import database_manager
database_manager.save_bar_data(bardatalist)

# 把历史数据BarData输出到csv
pd.DataFrame(bardatalist).to_csv("C:\Project\\"+ str(historyreq.symbol) + ".csv" , index=True, header=True)
print("History data export to CSV")

# # 参考backtesting.ipynb, 使用自带的双均线策略回测,10日上穿60日做多,否则反之
print("***从数据库读取历史数据, 进行回测***")
from vnpy.app.cta_strategy.backtesting import BacktestingEngine
from vnpy.app.cta_strategy.strategies.double_ma_strategy import (
    DoubleMaStrategy,
)
btengine = BacktestingEngine() #新建回测引擎
btengine.set_parameters(
    vt_symbol="12087792.IDEALPRO",
    interval="1m",
    start=datetime(2019, 9, 1),
    end=datetime(2019, 10, 5),
    rate = 0,
    slippage=0.00005,
    size=1000,
    pricetick=0.00005,
    capital=1_000_000,
)
btengine.add_strategy(DoubleMaStrategy, {"fast_window":10, "slow_window": 60})

btengine.load_data()
btengine.run_backtesting()
df = btengine.calculate_result()
btengine.calculate_statistics()
btengine.show_chart()

# 给script_engine载入双均线策略,实盘运行
print("***从数据库读取准备数据, 实盘运行***")
# 使用cta交易引擎
from vnpy.app.cta_strategy import CtaStrategyApp
from vnpy.app.cta_strategy.base import EVENT_CTA_LOG
engine.event_engine.register(EVENT_CTA_LOG, process_log_event)
cta_engine = engine.main_engine.add_app(CtaStrategyApp) #加入app
cta_engine.init_engine()
cta_engine.add_strategy("DoubleMaStrategy","DoubleMaStrategy_IB_12087792_v1", "12087792.IDEALPRO",{"fast_window":10, "slow_window": 50})
sleep(10)
cta_engine.init_strategy("DoubleMaStrategy_IB_12087792_v1")
sleep(10)
cta_engine.start_strategy("DoubleMaStrategy_IB_12087792_v1")
Member
avatar
加入于:
帖子: 2
声望: 0

写的好,手动点赞!!!

Member
avatar
加入于:
帖子: 4
声望: 0

谢谢张老师!
我可以成功运行您的代码,除了实盘的那部分有点问题:
1) 初始化的时候还是使用了RQdata, 不是IB的数据源
2) 最后有报错, 请参看下面的log

最后有个问题,请问能不能回测基于多品种套利的策略?

-----------log----------------------

从数据库读取准备数据, 实盘运行
2019-10-16 20:43:56.730160 RQData数据接口初始化成功


UnboundLocalError Traceback (most recent call last)

<ipython-input-9-8f99f830ac94> in <module>
6 engine.event_engine.register(EVENT_CTA_LOG, process_log_event)
7 cta_engine = engine.main_engine.add_app(CtaStrategyApp) #加入app
----> 8 cta_engine.init_engine()
9 cta_engine.add_strategy("DoubleMaStrategy","DoubleMaStrategy_IB_12087792_v1", "12087792.IDEALPRO",{"fast_window":10, "slow_window": 50})
10 sleep(10)

~\vnpy\vnpy\app\cta_strategy\engine.py in init_engine(self)
105 """
106 self.init_rqdata()
--> 107 self.load_strategy_class()
108 self.load_strategy_setting()
109 self.load_strategy_data()

~\vnpy\vnpy\app\cta_strategy\engine.py in load_strategy_class(self)
752
753 path2 = Path.cwd().joinpath("strategies")
--> 754 self.load_strategy_class_from_folder(path2, "strategies")
755
756 def load_strategy_class_from_folder(self, path: Path, module_name: str = ""):

~\vnpy\vnpy\app\cta_strategy\engine.py in load_strategy_class_from_folder(self, path, module_name)
767 [module_name, filename.split(".")[0]])
768
--> 769 self.load_strategy_class_from_module(strategy_module_name)
770
771 def load_strategy_class_from_module(self, module_name: str):

UnboundLocalError: local variable 'strategy_module_name' referenced before assignment

Member
加入于:
帖子: 136
声望: 44

@char-charles
我估计应该是你只截取了实盘那一段代码跑,engine使用了默认配置。还是用完全代码,注释掉数据下载和回测。

能不能回测基于多品种套利的策略?
vnpy现在不能,要改的话也挺麻烦的,基本相当于重建一套回测系统

Member
avatar
加入于:
帖子: 2
声望: 0

运行到从IB读取历史数据这一步,程序就一直卡在那里,没有报错也没有返回。你遇到过这个问题吗?
我用的vnpy2

张国平 wrote:

刚好有个同学问怎么实现IB历史数据获取,和策略回测和实盘交易。想着熟悉vnpy2.0操作,就用Jupyter Notebook都是跑了一边。VNPY2.0的整体架构设计很有扩展性,而且调用也比起v1.0先进清晰很多,引擎加载调用非常方便。

讲讲注意点:

  1. IB接口历史数据大多是要收费的订阅的,如果收费会有报错信息提示,这里找个免费的作为使用。另外vnpy是按照最大6个月历史数据设计的。
  2. 数据库定义有个小坑,我是用mongodb的,在第一次填写 trader/setting.py中密码写错了,后面在trader/setting.py改发现怎么也改不好;原来当第一次维护后,配置会写入.vntrader/vt_setting,之后系统只会去.vntrader/vt_setting读取。去改vt_setting,而不是trader/setting.py。
  3. 使用CtaStrategyApp支持加入新策略,系统会自动输出json保持策略信息;所以第二次运行代码时候,会提示已经有了,不是问题。
  4. 我在代码里面把回测和实盘放在一次,如果直接跑下来可能会报错,建议跑实盘时候先注释的回测。
  5. 使用script_engine订阅历史数据是是默认从rqdata获取,vnpy v2.07 IB接口已经提供历史数据获取,这里创建HistoryRequest用main_engine来获取,

为了方便贴出来,改成.py代码格式,直接跑也没有问题。

from vnpy.app.script_trader import init_cli_trading
from vnpy.app.script_trader.cli import process_log_event
from vnpy.gateway.ib import IbGateway
from time import sleep
from datetime import datetime
import pandas as pd
# 连接到服务器
setting = {
    "TWS地址": "127.0.0.1",
    "TWS端口": 7497,
    "客户号":8 #每个链接用一个独立的链接号,一个IBAPI支持32个来同时链接
}
engine = init_cli_trading([IbGateway]) #返回Script_engine 示例,并且给main_engine注册了gateway
engine.connect_gateway(setting, "IB") #链接

# 查询资金 - 自动
sleep(10)
print("***查询资金和持仓***")
print(engine.get_all_accounts(use_df = True))
# 查询持仓
print(engine.get_all_positions(use_df = True))

# 订阅行情
from vnpy.trader.constant import Exchange
from vnpy.trader.object import SubscribeRequest
# 从我测试直接用Script_engine有问题,IB的品种太多,get_all_contracts命令不行,需要指定具体后才可以,这里使用main_engine订阅
req1 = SubscribeRequest("12087792",Exchange.IDEALPRO) #创建行情订阅
engine.main_engine.subscribe(req1,"IB")


# 使用script_engine订阅历史数据是从rqdata获取,vnpy v2.07已经提供历史数据获取,这里创建HistoryRequest来获取,
# 查询如果没有endtime,默认当前。返回历史数据输出到数据库和csv文件
# 关于api更多信息可以参见 https://interactivebrokers.github.io/tws-api/historical_bars.html
print("***从IB读取历史数据, 返回历史数据输出到数据库和csv文件***")
from vnpy.trader.object import HistoryRequest
from vnpy.trader.object import Interval
start = datetime.strptime('20190901', "%Y%m%d")

historyreq = HistoryRequest(
  symbol="12087792",
  exchange=Exchange.IDEALPRO,
  start=start,
  interval=Interval.MINUTE
)
# # 读取历史数据,并把历史数据BarData放入数据库
bardatalist = engine.main_engine.query_history(historyreq,"IB")
from vnpy.trader.database import database_manager
database_manager.save_bar_data(bardatalist)

# 把历史数据BarData输出到csv
pd.DataFrame(bardatalist).to_csv("C:\Project\\"+ str(historyreq.symbol) + ".csv" , index=True, header=True)
print("History data export to CSV")

# # 参考backtesting.ipynb, 使用自带的双均线策略回测,10日上穿60日做多,否则反之
print("***从数据库读取历史数据, 进行回测***")
from vnpy.app.cta_strategy.backtesting import BacktestingEngine
from vnpy.app.cta_strategy.strategies.double_ma_strategy import (
  DoubleMaStrategy,
)
btengine = BacktestingEngine() #新建回测引擎
btengine.set_parameters(
    vt_symbol="12087792.IDEALPRO",
    interval="1m",
    start=datetime(2019, 9, 1),
    end=datetime(2019, 10, 5),
    rate = 0,
    slippage=0.00005,
    size=1000,
    pricetick=0.00005,
    capital=1_000_000,
)
btengine.add_strategy(DoubleMaStrategy, {"fast_window":10, "slow_window": 60})

btengine.load_data()
btengine.run_backtesting()
df = btengine.calculate_result()
btengine.calculate_statistics()
btengine.show_chart()

# 给script_engine载入双均线策略,实盘运行
print("***从数据库读取准备数据, 实盘运行***")
# 使用cta交易引擎
from vnpy.app.cta_strategy import CtaStrategyApp
from vnpy.app.cta_strategy.base import EVENT_CTA_LOG
engine.event_engine.register(EVENT_CTA_LOG, process_log_event)
cta_engine = engine.main_engine.add_app(CtaStrategyApp) #加入app
cta_engine.init_engine()
cta_engine.add_strategy("DoubleMaStrategy","DoubleMaStrategy_IB_12087792_v1", "12087792.IDEALPRO",{"fast_window":10, "slow_window": 50})
sleep(10)
cta_engine.init_strategy("DoubleMaStrategy_IB_12087792_v1")
sleep(10)
cta_engine.start_strategy("DoubleMaStrategy_IB_12087792_v1")
Member
avatar
加入于:
帖子: 2
声望: 0

应该是程序有点问题,每次请求就会卡死,还会造成tws卡死。
我用ib_insync来请求历史数据就没问题

Member
加入于:
帖子: 136
声望: 44

读取历史数据卡死的,你要看看我第一篇文章,接受延时数据类型修改下;是这样子,IB返回的历史数据,延时数据的数据类型在vnpy里面没有定义,必须新增。

不是这个原因,看了下代码,因为我写的是按照2.06,现在新的2.08应该改了些东西,你可以试试直接用in自带

Member
avatar
加入于:
帖子: 6
声望: 0

bardatalist = engine.main_engine.query_history(historyreq,"IB")
请问大神,这句一直运行不完,如何解决。

Member
avatar
加入于:
帖子: 7
声望: 0

我也遇到了 bardatalist = engine.main_engine.query_history(historyreq,"IB") 卡死的问题.
还没有解决.

Member
avatar
加入于:
帖子: 7
声望: 0

目前暂时用ib_insync 拿到数据后再导入vnpy了.

Member
加入于:
帖子: 1
声望: 0

张老师你好,
我以前能运行你的代码,昨天升级到2.11版本, 在bardatalist = engine.main_engine.query_history(historyreq,"IB")后会报错说AttributeError: 'NoneType' object has no attribute 'conId'
请问是不是新版本哪里有改动?谢谢

Member
avatar
加入于:
帖子: 29
声望: 0

张老师您好,
我想尝试运行您的代码,但运行时总是提示如下错误:KeyError Traceback (most recent call last)

<ipython-input-1-946756fca01e> in <module>
12 }
13 engine = init_cli_trading([IbGateway]) #返回Script_engine 示例,并且给main_engine注册了gateway
---> 14 engine.connect_gateway(setting, "IB") #链接
15
16 # 查询资金 - 自动

c:\vnstudio\lib\site-packages\vnpy\app\script_trader\engine.py in connect_gateway(self, setting, gateway_name)
102 def connect_gateway(self, setting: dict, gateway_name: str):
103 """"""
--> 104 self.main_engine.connect(setting, gateway_name)
105
106 def send_order(

c:\vnstudio\lib\site-packages\vnpy\trader\engine.py in connect(self, setting, gateway_name)
164 gateway = self.get_gateway(gateway_name)
165 if gateway:
--> 166 gateway.connect(setting)
167
168 def subscribe(self, req: SubscribeRequest, gateway_name: str) -> None:

c:\vnstudio\lib\site-packages\vnpy\gateway\ib\ib_gateway.py in connect(self, setting)
164 port = setting["TWS端口"]
165 clientid = setting["客户号"]
--> 166 account = setting["交易账户"]
167
168 self.api.connect(host, port, clientid, account)

KeyError: '交易账户'
想请教下解决方法。谢谢!

Member
avatar
加入于:
帖子: 6
声望: 0

Traceback (most recent call last):
File "/usr/local/Homebrew/Library/Taps/homebrew/vnpy/examples/vn_trader/ibtest_20200704.py", line 31, in <module>
engine.main_engine.subscribe(req1,"IB")

gateway.subscribe(req)

File "/anaconda3/lib/python3.7/site-packages/vnpy/gateway/ib/ib_gateway.py", line 191, in subscribe
self.api.subscribe(req)
File "/anaconda3/lib/python3.7/site-packages/vnpy/gateway/ib/ib_gateway.py", line 663, in subscribe
if req.vt_symbol in self.subscrbied:
AttributeError: 'IbApi' object has no attribute 'subscrbied'

您好,这个订阅行情这里报错呢,请教下呢如何解决呢

Member
avatar
加入于:
帖子: 1
声望: 0

晴之 wrote:

Traceback (most recent call last):
File "/usr/local/Homebrew/Library/Taps/homebrew/vnpy/examples/vn_trader/ibtest_20200704.py", line 31, in <module>
engine.main_engine.subscribe(req1,"IB")

gateway.subscribe(req)

File "/anaconda3/lib/python3.7/site-packages/vnpy/gateway/ib/ib_gateway.py", line 191, in subscribe
self.api.subscribe(req)
File "/anaconda3/lib/python3.7/site-packages/vnpy/gateway/ib/ib_gateway.py", line 663, in subscribe
if req.vt_symbol in self.subscrbied:
AttributeError: 'IbApi' object has no attribute 'subscrbied'

您好,这个订阅行情这里报错呢,请教下呢如何解决呢

有部份字句错了,打开ib_gateway.py,搜"subscrbied",应该有两处,都改成"subscribed"即可

Member
avatar
加入于:
帖子: 6
声望: 0

edmundc wrote:

晴之 wrote:

Traceback (most recent call last):
File "/usr/local/Homebrew/Library/Taps/homebrew/vnpy/examples/vn_trader/ibtest_20200704.py", line 31, in <module>
engine.main_engine.subscribe(req1,"IB")

gateway.subscribe(req)

File "/anaconda3/lib/python3.7/site-packages/vnpy/gateway/ib/ib_gateway.py", line 191, in subscribe
self.api.subscribe(req)
File "/anaconda3/lib/python3.7/site-packages/vnpy/gateway/ib/ib_gateway.py", line 663, in subscribe
if req.vt_symbol in self.subscrbied:
AttributeError: 'IbApi' object has no attribute 'subscrbied'

您好,这个订阅行情这里报错呢,请教下呢如何解决呢

有部份字句错了,打开ib_gateway.py,搜"subscrbied",应该有两处,都改成"subscribed"即可

已经解决了,多谢呀~~

Member
avatar
加入于:
帖子: 102
声望: 2
from vnpy.app.script_trader import init_cli_trading
from vnpy.app.script_trader.cli import process_log_event
from vnpy.gateway.ib import IbGateway
from time import sleep
from datetime import datetime
import pandas as pd
from vnpy.trader.object import HistoryRequest
from vnpy.trader.object import Interval
from vnpy.trader.constant import Exchange
from vnpy.trader.object import SubscribeRequest


setting = {
        "TWS地址": "127.0.0.1",
        "TWS端口": 7497,
        "客户号": 1,
        "交易账户": ""
    }
engine = init_cli_trading([IbGateway]) #返回Script_engine 示例,并且给main_engine注册了gateway
engine.connect_gateway(setting, "IB") #链接

req1 = SubscribeRequest("EUR-USD-CASH", Exchange.IDEALPRO)  # 创建行情订阅
engine.main_engine.subscribe(req1, "IB")

start = datetime.strptime("20210309 16:30:00", "%Y%m%d %H:%M:%S")
end = datetime.strptime("20210310 23:30:00", "%Y%m%d %H:%M:%S")
print(start)
historyreq = HistoryRequest(
        symbol="EUR-USD-CASH",
        exchange=Exchange.IDEALPRO,
        start=start,
        end = end,
        interval=Interval.DAILY
)

bardatalist = engine.main_engine.query_history(historyreq,"IB")
print(bardatalist)

以上是代码,运行错误如下

2021-03-11 01:39:07.298561  信息通知,代码:2158,内容: Sec-def data farm connection is OK:secdefhk
2021-03-11 01:39:07.298561  当前使用的交易账号为DU3607836
2021-03-11 01:39:07.298561  服务器时间: 2021-03-11 01:39:10.000000
Exception in thread Thread-4:
Traceback (most recent call last):
  File "C:\vnstudio\lib\threading.py", line 917, in _bootstrap_inner
    self.run()
  File "C:\vnstudio\lib\threading.py", line 865, in run
    self._target(*self._args, **self._kwargs)
  File "C:\vnstudio\lib\site-packages\vnpy\gateway\ib\ib_gateway.py", line 832, in run
    self.decoder.interpret(fields)
  File "C:\vnstudio\lib\site-packages\ibapi\decoder.py", line 1280, in interpret
    handleInfo.processMeth(self, iter(fields))
  File "C:\vnstudio\lib\site-packages\ibapi\decoder.py", line 517, in processHistoricalDataMsg
    self.wrapper.historicalData(reqId, bar)
  File "C:\vnstudio\lib\site-packages\vnpy\gateway\ib\ib_gateway.py", line 605, in historicalData
    dt = datetime.strptime(ib_bar.date, "%Y%m%d %H:%M:%S")
  File "C:\vnstudio\lib\_strptime.py", line 577, in _strptime_datetime
    tt, fraction, gmtoff_fraction = _strptime(data_string, format)
  File "C:\vnstudio\lib\_strptime.py", line 359, in _strptime
    (data_string, format))
ValueError: time data '20210310' does not match format '%Y%m%d %H:%M:%S'

请指点,问题是什么??

Member
avatar
加入于:
帖子: 3027
声望: 174

你的时间格式和填的默认的格式不同,默认时间格式为"%Y-%m-%d %H:%M:%S",对应的是"2017-1-3 0:00:00"

Member
avatar
加入于:
帖子: 102
声望: 2

代码改成这样。

start = datetime.strptime("2021-3-9 16:30:00", "%Y-%m-%d %H:%M:%S")
end = datetime.strptime("2021-3-11 20:30:00", "%Y-%m-%d %H:%M:%S")

然后

2021-03-11 22:11:54,165  INFO: 信息通知,代码:2158,内容: Sec-def data farm connection is OK:secdefhk
2021-03-11 22:11:54,165  INFO: 当前使用的交易账号为DU3607836
2021-03-11 22:11:54,165  INFO: 服务器时间: 2021-03-11 22:11:56.000000
Exception in thread Thread-4:
Traceback (most recent call last):
  File "C:\vnstudio\lib\threading.py", line 917, in _bootstrap_inner
    self.run()
  File "C:\vnstudio\lib\threading.py", line 865, in run
    self._target(*self._args, **self._kwargs)
  File "C:\vnstudio\lib\site-packages\vnpy\gateway\ib\ib_gateway.py", line 832, in run
    self.decoder.interpret(fields)
  File "C:\vnstudio\lib\site-packages\ibapi\decoder.py", line 1280, in interpret
    handleInfo.processMeth(self, iter(fields))
  File "C:\vnstudio\lib\site-packages\ibapi\decoder.py", line 517, in processHistoricalDataMsg
    self.wrapper.historicalData(reqId, bar)
  File "C:\vnstudio\lib\site-packages\vnpy\gateway\ib\ib_gateway.py", line 605, in historicalData
    dt = datetime.strptime(ib_bar.date, "%Y%m%d %H:%M:%S")
  File "C:\vnstudio\lib\_strptime.py", line 577, in _strptime_datetime
    tt, fraction, gmtoff_fraction = _strptime(data_string, format)
  File "C:\vnstudio\lib\_strptime.py", line 359, in _strptime
    (data_string, format))
ValueError: time data '20210310' does not match format '%Y%m%d %H:%M:%S'

结果依旧如此。

Member
avatar
加入于:
帖子: 102
声望: 2

改成这样(就是3月变成03月)

start = datetime.strptime("2021-03-09 16:30:00", "%Y-%m-%d %H:%M:%S")
end = datetime.strptime("2021-03-11 20:30:00", "%Y-%m-%d %H:%M:%S")

结果和上面一样。

Member
avatar
加入于:
帖子: 3027
声望: 174

你的start和end是发出去的,报错的应该是收到的数据的datetime处理。
你查的日线,可能返回的时候只有日期没有时分秒,你报错的地方在File "C:\vnstudio\lib\site-packages\vnpy\gateway\ib\ib_gateway.py", line 605, in historicalData,可以在这里打印一下

© 2015-2019 上海韦纳软件科技有限公司
备案服务号:沪ICP备18006526号-3

沪公网安备 31011502017034号