VeighNa量化社区
你的开源社区量化交易平台
tonywang_efun's Avatar
Member
在线
48 帖子
声望: 12

NO_UI启动程序,非交易期间子进程没有完全关闭,如下图所示:7点31分还收到了一条bar推送。请问有办法解决吗 ?

description

我在MAC电脑上使用TTS接口报错,请问需要如何解决?

Traceback (most recent call last):
File "/Users/wangxudong/code/vnpy/vnpy/run.py", line 6, in <module>
from vnpy_tts import TtsGateway
File "/Users/wangxudong/miniconda3/envs/vnpy/lib/python3.10/site-packages/vnpy_tts/init.py", line 25, in <module>
from .gateway import TtsGateway
File "/Users/wangxudong/miniconda3/envs/vnpy/lib/python3.10/site-packages/vnpy_tts/gateway/init.py", line 1, in <module>
from .tts_gateway import TtsGateway
File "/Users/wangxudong/miniconda3/envs/vnpy/lib/python3.10/site-packages/vnpy_tts/gateway/tts_gateway.py", line 32, in <module>
from ..api import (
File "/Users/wangxudong/miniconda3/envs/vnpy/lib/python3.10/site-packages/vnpy_tts/api/init.py", line 1, in <module>
from .vnttsmd import MdApi
ModuleNotFoundError: No module named 'vnpy_tts.api.vnttsmd'

运行vnpy项目examples/cta_backtesting/portfolio_backtesting.ipynb 文件,时间选择从2010-1-1 到2023-4-30发现2020之后回撤不断放大,请问是样本外的原因还是市场风格转换导致的?

description

采用TTS接口进行模拟盘交易发现委托价格差别很大 , 具体如下图所示,交易界面显示委托价格3354,策略界面显示的价格是3748,请问大佬3354这个价格是不是显示错误了?

description

description

商品期货在2014年后发生了啥,好多策略和品种都在2014年后收益锐减,有大佬知道发生了啥事吗?

description

用RQData的RB888的数据跑回测发现有负数的成交价,是因为平滑处理造成的吗,会不会对策略结果造成影响呢?

description

1)策略中的variables变量会在停止策略时写入策略数据文件:cta_strategy_data.json 中
2)每次初始策略会先加载数据然后用cta_strategy_data.json文件的内容重置策略变量,代码如下:

        self.write_log(f"{strategy_name}开始执行初始化")

        # Call on_init function of strategy
        self.call_strategy_func(strategy, strategy.on_init)

        # Restore strategy data(variables)
        data = self.strategy_data.get(strategy_name, None)
        if data:
            for name in strategy.variables:
                value = data.get(name, None)
                if value:
                    setattr(strategy, name, value)

3)假设策略用到的交易高点被记录到变量中 variables = ['intraTradeHigh'],则可能引发问题如下:

  9月1号 开仓做多,成交价 = 98,停止策略时 记录 intraTradeHigh = 100
  9月2号 没有启动策略交易 当天最高价 = 110
  9月3号 开启策略时候会用策略文件中的 100 设置intraTradeHigh值,这样就漏掉了2号的最高价110,可能对交易策略产生一定影响。

粗略的分析,欢迎大佬拍砖指正~

我的米筐账号试用期到了,看到张国平一篇聚宽的接入文章《利用聚宽(Joinquant)数据源为vnpy添加期货行情数据》深受启发,整了一个聚宽数据(JDDataSDK)集成方案,可以和米筐数据并存,自由配置切换,具体特性如下:
1)抽象了行情数据接口
2)实现了vn_symobl到jq_symbol的转换
3)避免了jqdata在交易日自动填充交易量为0的脏数据BUG,原理参考国平的文章《如果使用Joinquant做实盘行情数据,有一个比较大bug的要注意
4)实现了和VNPY的深度集成,可以采用VNPY的配置界面实现傻瓜式配置。

聚宽数据的具体介绍,包括如何申请账号在国平的文章里已经写得很清楚了,需要了解的兄弟可以参考上文链接,本文主要介绍如何与VNPY集成在一起。

第一步:配置行情数据源,具体如下图所示:

description

行情配置的代码很简单,在setting.py文件里加上三行代码即可,具体如下:

    "mddata.api": "rqdata",

    "jqdata.username": "",
    "jqdata.password": "",

第二步:抽象了行情数据接口,所有文件集中在 trader/mddata 文件夹中:

description

dataapi.py文件是抽象类:

from abc import ABC, abstractmethod

from vnpy.trader.object import HistoryRequest


class MdDataApi(ABC):
    """
    抽象数据接口
    """

    @abstractmethod
    def init(self, username="", password=""):
        """
        初始化行情数据接口
        :param username: 用户名
        :param password: 密码
        :return:
        """
        pass

    @abstractmethod
    def query_history(self, req: HistoryRequest):
        """
        查询历史数据接口
        :param req:
        :return:
        """
        pass

jqdata.py是聚宽数据接口的具体实现

import jqdatasdk as jq

from datetime import timedelta, datetime
from typing import List

from vnpy.trader.constant import Exchange, Interval
from vnpy.trader.mddata.dataapi import MdDataApi
from vnpy.trader.object import BarData, HistoryRequest
from vnpy.trader.setting import SETTINGS

INTERVAL_VT2JQ = {
    Interval.MINUTE: "1m",
    Interval.HOUR: "60m",
    Interval.DAILY: "1d",
}

INTERVAL_ADJUSTMENT_MAP_JQ = {
    Interval.MINUTE: timedelta(minutes=1),
    Interval.HOUR: timedelta(hours=1),
    Interval.DAILY: timedelta()  # no need to adjust for daily bar
}


class JqdataClient(MdDataApi):
    """聚宽JQData客户端封装类"""

    def __init__(self):
        """"""
        self.username = SETTINGS["jqdata.username"]
        self.password = SETTINGS["jqdata.password"]

        self.inited = False

    def init(self, username="", password=""):
        """"""
        if self.inited:
            return True

        if username and password:
            self.username = username
            self.password = password

        if not self.username or not self.password:
            return False

        try:
            jq.auth(self.username, self.password)
        except Exception as ex:
            print("jq auth fail:" + repr(ex))
            return False

        self.inited = True
        return True

    def to_jq_symbol(self, symbol: str, exchange: Exchange):
        """
        CZCE product of RQData has symbol like "TA1905" while
        vt symbol is "TA905.CZCE" so need to add "1" in symbol.
        """
        if exchange in [Exchange.SSE, Exchange.SZSE]:
            if exchange == Exchange.SSE:
                jq_symbol = f"{symbol}.XSHG"  # 上海证券交易所
            else:
                jq_symbol = f"{symbol}.XSHE"  # 深圳证券交易所
        elif exchange == Exchange.SHFE:
            jq_symbol = f"{symbol}.XSGE"  # 上期所
        elif exchange == Exchange.CFFEX:
            jq_symbol = f"{symbol}.CCFX"  # 中金所
        elif exchange == Exchange.DCE:
            jq_symbol = f"{symbol}.XDCE"  # 大商所
        elif exchange == Exchange.INE:
            jq_symbol = f"{symbol}.XINE"  # 上海国际能源期货交易所
        elif exchange == Exchange.CZCE:
            # 郑商所 的合约代码年份只有三位 需要特殊处理
            for count, word in enumerate(symbol):
                if word.isdigit():
                    break

            # Check for index symbol
            time_str = symbol[count:]
            if time_str in ["88", "888", "99", "8888"]:
                return symbol

            # noinspection PyUnboundLocalVariable
            product = symbol[:count]
            year = symbol[count]
            month = symbol[count + 1:]

            if year == "9":
                year = "1" + year
            else:
                year = "2" + year

            jq_symbol = f"{product}{year}{month}.XZCE"

        return jq_symbol.upper()

    def query_history(self, req: HistoryRequest):
        """
        Query history bar data from JQData.
        """
        symbol = req.symbol
        exchange = req.exchange
        interval = req.interval
        start = req.start
        end = req.end

        jq_symbol = self.to_jq_symbol(symbol, exchange)
        # if jq_symbol not in self.symbols:
        #     return None

        jq_interval = INTERVAL_VT2JQ.get(interval)
        if not jq_interval:
            return None

        # For adjust timestamp from bar close point (RQData) to open point (VN Trader)
        adjustment = INTERVAL_ADJUSTMENT_MAP_JQ.get(interval)

        # For querying night trading period data
        # end += timedelta(1)
        now = datetime.now()
        if end >= now:
            end = now
        elif end.year == now.year and end.month == now.month and end.day == now.day:
            end = now

        df = jq.get_price(
            jq_symbol,
            frequency=jq_interval,
            fields=["open", "high", "low", "close", "volume"],
            start_date=start,
            end_date=end,
            skip_paused=True
        )

        data: List[BarData] = []

        if df is not None:
            for ix, row in df.iterrows():
                bar = BarData(
                    symbol=symbol,
                    exchange=exchange,
                    interval=interval,
                    datetime=row.name.to_pydatetime() - adjustment,
                    open_price=row["open"],
                    high_price=row["high"],
                    low_price=row["low"],
                    close_price=row["close"],
                    volume=row["volume"],
                    gateway_name="JQ"
                )
                data.append(bar)

        return data


jqdata_client = JqdataClient()

rqdata.py文件是VNPY已经提供的米筐数据接口实现,这里就改了一句,增加对标准接口MdDataApi的继承

class RqdataClient(MdDataApi):

init.py文件会根据setting.py的配置文件加载具体的行情数据接口

from vnpy.trader.mddata.dataapi import MdDataApi
from vnpy.trader.mddata.jqdata import jqdata_client
from vnpy.trader.mddata.rqdata import rqdata_client
from vnpy.trader.setting import SETTINGS

if SETTINGS["mddata.api"] == "jqdata":
    mddata_client: MdDataApi = jqdata_client
else:
    mddata_client: MdDataApi = rqdata_client

第三步:使用mddata_client替换rqdata_client即可,例如cta_strategy/engine.py文件的改造如下:
注意:script_trader/engine.py,cta_backtester/engine.py,cta_strategy/engine.py 这三个文件都要改造

from vnpy.trader.mddata import mddata_client

    def init_rqdata(self):
        """
        Init RQData client.
        """
        result = mddata_client.init()
        md_data_api = SETTINGS["mddata.api"]
        if result:
            self.write_log(f"{md_data_api}数据接口初始化成功")

    def query_bar_from_rq(
        self, symbol: str, exchange: Exchange, interval: Interval, start: datetime, end: datetime
    ):
        """
        Query bar data from RQData.
        """
        req = HistoryRequest(
            symbol=symbol,
            exchange=exchange,
            interval=interval,
            start=start,
            end=end
        )

        try:
            data = mddata_client.query_history(req)
        except Exception as ex:
            self.write_log(f"{symbol}.{exchange.value}合约下载失败:{ex.args}")
            return None

        return data

如下图所示:同一个Enum值比较却不相同,没查到资料,有没有大神指点一下

description

description

我用BollingerBotStrategy策略稍微改造了一下,用在RB1901上感觉还可以,但是换到其它品种就一塌糊涂了

description

  def to_rq_symbol(self, symbol: str, exchange: Exchange):
    """
    CZCE product of RQData has symbol like "TA1905" while
    vt symbol is "TA905.CZCE" so need to add "1" in symbol.
    """

为什么vt symbol 必须是TA905,而不能用TA1905呢?

阅读了几天VNPY的代码,梳理的一份代码框架图,请大佬们拍砖~

description

© 2015-2022 微信 18391752892
备案服务号:沪ICP备18006526号

沪公网安备 31011502017034号

【用户协议】
【隐私政策】
【免责条款】