VeighNa量化社区
你的开源社区量化交易平台
ahren's Avatar
Member
离线
101 帖子
声望: 5

MTF wrote:

回测时,获取的是你在回测引擎中设置的合约乘数。

实盘时,获取的是交易接口返回的合约数据中的乘数字段。

明白了,多谢!

1.Lib\site-packages\vnpy路径下新建user_tools文件夹,放入pricetick.py
pricetick.py内容如下:

import json
import os
class PRICETICK(object):
    PATH = os.environ["USERPROFILE"] + "\\.vntrader\\unit.json"
    PRICE_TICK = 0.0  #最小跳动点 float
    UNIT = 0           #合约乘数 int

    def get_unit(self,symbol):
        with open(self.PATH,"r",encoding="utf_8") as f:
            result = json.load(f)
        for key_symbol in result:
            if key_symbol == symbol:
                self.PRICE_TICK = float(result[symbol][0])  #json读取最小跳动点
                self.UNIT = int(result[symbol][1])          #json读取合约乘数
                break
        return self.PRICE_TICK,self.UNIT

2. .vntrader\unit.json 在.\vntrader文件夹下,新建unit.json, json文件存储所有标的最小跳动点,合约乘数
unit.json内容如下:

{    
    "IF":["0.2","300"],
    "IC":["0.2","200"],
    "IH":["0.2","300"],
    "IM":["0.2","200"],
    "T":["0.005","10000"],
    "TF":["0.005","10000"],
    "TS":["0.005","20000"],
    "TL":["0.01","10000"],
    "AU":["0.02","1000"],
    "AG":["1","15"],
    "CU":["10","5"],
    "AL":["5","5"],
    "ZN":["5","5"],
    "PB":["5","5"],
    "NI":["10","1"],
    "SN":["10","1"],
    "RB":["1","10"],
    "WR":["1","10"],
    "I":["0.5","100"],
    "HC":["1","10"],
    "SS":["5","5"],
    "SF":["2","5"],
    "SM":["2","5"],
    "JM":["0.5","60"],
    "J":["0.5","100"],
    "ZC":["0.2","100"],
    "FG":["1","20"],
    "SP":["2","10"],
    "FU":["1","10"],
    "LU":["1","10"],
    "SC":["0.1","1000"],
    "BC":["10","5"],
    "EC":["0.1","50"],
    "BU":["1","10"],
    "PG":["1","20"],
    "RU":["5","10"],
    "NR":["5","10"],
    "L":["1","5"],
    "TA":["2","5"],
    "V":["1","5"],
    "EG":["1","10"],
    "MA":["1","10"],
    "PP":["1","5"],
    "EB":["1","5"],
    "UR":["1","20"],
    "SA":["1","20"],
    "C":["1","10"],
    "A":["1","10"],
    "CS":["1","10"],
    "B":["1","10"],
    "M":["1","10"],
    "Y":["2","10"],
    "RM":["1","10"],
    "OI":["1","10"],
    "P":["2","10"],
    "CF":["5","5"],
    "SR":["1","10"],
    "JD":["1","10"],
    "AP":["1","10"],
    "CJ":["5","5"],
    "PF":["2","5"],
    "PK":["2","5"],
    "AO":["1","20"],
    "LC":["50","1"],
    "SI":["5","5"],
    "BR":["5","5"],
    "RR":["1","10"],
    "LH":["5","16"],
    "PX":["2","5"],
    "SH":["1","30"]
}

3.在自己的策略中调用

from vnpy.user_tools.pricetick import PRICETICK   
初始化时候def __init__():
实例化 self.contract = PRICETICK()
获取标的   self.symbol = "".join(re.findall(r"\D+",self.get_data()["vt_symbol"].split(".")[0])).upper()
提取最小变动价格,合约乘数   self.PRICE_TICK,self.UNIT = self.contract.get_unit(self.symbol)  #从json提取最小变动价位,合约乘数

ahren wrote:

xiaohe wrote:

  1. 要load_bar完成后(初始化完成后),trading状态才会变为true。
  2. 可以去engine.py看一下load_bar函数。默认use_database为false,会先去接口拿数据,没有的话会去rqdata找,最后才会去database。

数据库存储了足够的日线历史数据,没有存储分钟数据,然后self.load_bar(days = 40,use_database=True),40个自然日足够策略计算指标,在cta策略界面执行初始化,看了下初始化inited=True,启动后trading=True,但显示窗口列出的指标都没有数据,就能不通过rqdata实现实盘交易吗?
不能的话,只想通过数据库历史数据,不要rqdata的数据,数据库是不是还需要历史分钟数据才可以,至少需要多少分钟数据?

验证了下,load_bar(10), 实盘是load 10个自然日的1分钟线去初始化(开始以为是10个自然日日线数据就可以初始化),那么不用rqdata的历史数据,数据库必须写入的是满足load_bar天数的1分钟线,如果天数不满足依然可以初始化,只是指标可能就计算不出来;我的策略指标都是日线计算,但cta策略合成日线又都是用分钟数据,在想数据库存日线数据容易获取,直接用日线数据计算指标而不通过分钟合成日线在计算指标,不就可以实现入库的是日线历史数据,而实现策略初始化

xiaohe wrote:

  1. 要load_bar完成后(初始化完成后),trading状态才会变为true。
  2. 可以去engine.py看一下load_bar函数。默认use_database为false,会先去接口拿数据,没有的话会去rqdata找,最后才会去database。

数据库存储了足够的日线历史数据,没有存储分钟数据,然后self.load_bar(days = 40,use_database=True),40个自然日足够策略计算指标,在cta策略界面执行初始化,看了下初始化inited=True,启动后trading=True,但显示窗口列出的指标都没有数据,就能不通过rqdata实现实盘交易吗?
不能的话,只想通过数据库历史数据,不要rqdata的数据,数据库是不是还需要历史分钟数据才可以,至少需要多少分钟数据?

CtaTemplate中,cta_engine.get_size()这个合约乘数获取,是从接入的数据源获得的嘛?比如接入rqdata,这个get_size()数据就是rqdata的数据

搞清楚了,记录下过程,本人爬到的数据以dataframe形式缓存,其中日期是str形式存储,按照论坛内容转换df["date"] = pd.to_datetime(df["date"],format = '%Y%m%d %H:%M:%S'),此时日期时间存储形式是Timestamp(时间戳),且没有时区属性, 而bardata 入sqlite 需要以带有时间戳的datetime形式存储,所以需要增加时区属性,同时将Timestamp形式变成datetime形式;合成bardata时处理如下:
datetime = datetime.fromtimestamp(int(row.datetime.timestamp()),pytz.timezone('Asia/Shanghai'));
因为sqlite 版本不同,时间存储Timestamp,datatime形式有区别,参考 https://baijiahao.baidu.com/s?id=1671113933155288895&wfr=spider&for=pc

我的数据是交易所每个交易日所有合约开盘、最高、最低、收盘等数据,而不是按照单一合约按照交易日排序的数据,直接用下面的方法入库,看了下数据库dbbardata入了所有数据,但映射到dbbaroverview 就不是每个合约按照日期排序,清空dbbaroverview数据,在数据管理窗口刷新下,才能映射成功,
1.有什么方法可以直接入库映射成功呢?
2.本地sqlite数据库存储了数据,且映射成功,在cta策略窗口,在不接入rqdata情况下,执行初始化依然没有历史数据初始化,这个初始化难道不是先从sqlite数据库读历史数据?
3.接入的rqdata数据,通过vnstation界面,cta策略初始化的数据,在数据库里面都没找到,这个初始化数据存储在哪儿呢?
from vnpy.trader.database import BaseDatabase, get_database
database: BaseDatabase = get_database()
database.save_bar_data(bars)

按照这个 Debug过程请参考 https://github.com/Yiran13/Strategies/tree/master/debug_process ,bardata中datetime要储存为str形式,可把datetime变成str形式,database.save_bar_data(bars)入库sqlite时候,报错AttributeError: 'str' object has no attribute 'astimezone'; 如果datetime变成Timestamp形式存储,报错InterfaceError: Error binding parameter 2 - probably unsupported type.

xiaohe wrote:

是你datetime类型的问题,可参考https://www.vnpy.com/forum/topic/4137-qing-jiao-:-csvwen-jian-yong-jiao-ben-dao-ru-sqlitebao-cuo-shi-qu-fang-mian
按照原贴12,13楼添加了时区,如下图

description

from vnpy.trader.database import BaseDatabase, get_database
insert into database
database: BaseDatabase = get_database()
database.save_bar_data(bars)

但按照这种方法入库,报错,Error binding parameter 2 - probably unsupported type.检查了下只有枚举类型,时间戳,float数据类型都能对得上;
现在这个sqlite_manager怎么创建的?我换成sqlite_manager.save_bar_data(bars)试试

MTF wrote:

版本太老了吧,综合升级到3.8.0试试

应该不是版本问题,现在是3.7.0版本

description

description

dataframe 数据,如上图,需要数据入库SqliteDatabase,先已经将dataframe数据整理成BarData
入库如下:

_from vnpy.trader.database import BaseDatabase, get_database
database: BaseDatabase = get_database()
database.save_bardata(bars)

description
遇到这个时间戳转换问题,如何解决呢?

这样是不是复杂了啊?或许试试,在每一次on_trade里关注trade的开平状态,只要是开仓的话就发出止损单。不需要查看之前是否发出止损单,只要是最新on_trade的开仓,之前一定是没有发过的。

按照你的方法,可以的,不用判断直接发止损单,谢啦

alvinli512 wrote:

“先判断没发出止损单”这个判断是通过之前的order id吗。或许可以用trade id来判断?

是的,之前按照orderid来判断的,想了下tradeid 可以,你看看这么实现有没有漏洞
on_trade()里面先long_tradeid = [],short_tradeid = []缓存tradeid,接着
self.pos != 0时候获取trade.price,不同的方向上把trade.tradeid 分别加入对应的tradeid 列表,即:long_tradeid.extend(trade.tradeid)
self.pos > 0 时候 判断有long_tradeid,计算long_stop,然后遍历long_tradeid,发出止损单
即:self.sell(self.long_stop,abs(trade.volume),stop=True);反之,self.pos<0同样;
这样的话,就是循环成交笔次数挂止损单,没有剔除tradeid list ;

xiaohe wrote:

on_trade/on_tick都可以自己打印看看是否符合你的猜想

on_trade 里面打印trade.volume ,1单被拆成2笔成交,trade.volume回报的是2笔,时间戳毫秒有点区别;第一笔成交后,立即就发出了第一笔的止损单;因为在发出止损单前,有先判断没发出止损单,才计算止损价格发出止损单,导致第二笔止损单发不出去;目前不清楚删掉判断有没有发止损单这个条件,会不会影响其他部分

xiaohe wrote:

正常分次成交情况下,应该每一次都会收到on_trade推送,应该首先在on_trade下打印排查这个问题
不清楚你策略的具体逻辑,如果想开仓后立即挂单,可以在on_trade下进行委托

on_trade里面就是仓位大于0,判断没有挂止损单就发出trade.volume量的止损单,self.sell(self.long_stop,abs(trade.volume),stop=True)(仓位小于0,判断没挂止损,发trade.volume量的止损);
我怀疑是因为在on_tick里面 把tick数据推送到on_bar,导致on_bar时时刻刻都在接受tick数据,而不是每分钟合成好k线才有数据

alvinli512 wrote:

ahren wrote:

alvinli512 wrote:
如果只成交了33,那就只下了两个停止单,量分别是33,因为on_trade只被调用了两次。

这样依然不行,用trade.volume 发出的止损,也是首次成交的单子,也就是您讲的只发出了3;

alvinli512 wrote:

可以在每次on_trade下查看仓位,如果大于0,用trade.volume来下停止单。就只下每次成交量的停止单数量。

就是说我在仓位不等于0时候,缓存trade.volume,来替换止损单中的self.pos?

连龙八卦 wrote:

挂止损单不用在on_trade函数下面回调,在每根k来的时候都挂即可。

我是要开仓立即发止损单

在on_trade函数下,判断self.pos>0,且没有挂止损单,发出止损self.sell(stop_price,abs(self.pos),stop=True),最后发现发出去的止损单和仓位不一致;观察了下,可能是一个仓位分了多次成交,on_trade只收到第一单成交的仓位,这个如何解决?

MTF wrote:

无法替换,如果必须使用3.10.2以外版本的话,推荐用【官方Python解释器+手动安装】的方案了

就是装2个不同的python?

vnpy自带的python3.10.2 版本,对以前自己写的程序不兼容,怎么简单更换vnpy自带的版本不影响vnstation现有的程序?

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

沪公网安备 31011502017034号

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