从委托到接受、等待、部分成交、全部成交,需要一个过程,你以为象计算机指令一样C=A+B,这边执行,那边就可以得到C的结果吗?
在on_tick()中下单,每秒钟2次,怎么可能立即都有成交结果,没有成交结果,怎么self.pos会发生变化?当然会连续下单,“基本上判断pos废了”就是错误 的!
很久没有升级了,今天升级了。发现很多新的东西,不知道有什么有,问问官方QuoteRequest有什么用?
list text here在vnpy>trader>object.py中增加了下面的代码:
@dataclass
class QuoteRequest:
"""
Request sending to specific gateway for creating a new quote.
"""
symbol: str
exchange: Exchange
bid_price: float
bid_volume: int
ask_price: float
ask_volume: int
bid_offset: Offset = Offset.NONE
ask_offset: Offset = Offset.NONE
reference: str = ""
def __post_init__(self):
""""""
self.vt_symbol = f"{self.symbol}.{self.exchange.value}"
def create_quote_data(self, quoteid: str, gateway_name: str) -> QuoteData:
"""
Create quote data from request.
"""
quote = QuoteData(
symbol=self.symbol,
exchange=self.exchange,
quoteid=self.quoteid,
bid_price=self.bid_price,
bid_volume=self.bid_volume,
ask_price=self.ask_price,
ask_volume=self.ask_volume,
bid_offset=self.bid_offset,
ask_offset=self.ask_offset,
reference=self.reference,
gateway_name=gateway_name,
)
return quote
在vnpy>trader>gateway.py中的BaseGateway类型总增加了下面的函数:
def send_quote(self, req: QuoteRequest) -> str:
"""
Send a new two-sided quote to server.
implementation should finish the tasks blow:
* create an QuoteData from req using QuoteRequest.create_quote_data
* assign a unique(gateway instance scope) id to QuoteData.quoteid
* send request to server
* if request is sent, QuoteData.status should be set to Status.SUBMITTING
* if request is failed to sent, QuoteData.status should be set to Status.REJECTED
* response on_quote:
* return vt_quoteid
:return str vt_quoteid for created QuoteData
"""
return "" # 返回了空字符串,
返回了空字符串,其实什么用也没有,一个接口类函数。貌似是让其他的派生的特定网关来实现这个函数。
可是我查询了下,CTP、XTP等网关,没有一个实现了该函数,系统中也没有任何一个地方直接或者间接低调用过该send_quote()函数。
是的,保存到数据库也是可以的。不过还是比较复杂的。
股票、期货合约都有集合竞价时段,如国内期货合约为前一交易日的21:00前5分钟,股指期货合约为当前交易日的9:30前5分钟,股票合约的为当前交易日的9:30之前。
集合竞价完成之后通常在开市前1分钟提供CTP接口推送第一个tick,注意:这个tick的时间戳为开市前1分钟,而不在各个交易时间段内!
如:
国内期货合约如果第一个交易段为21:00,那么这个tick的时间戳为20:59
国内股指期货合约为当前交易日的9:30,那么这个tick的时间戳为9:29
实盘中每个合约都会有集合竞价时段,这时候采用自带的BarGenerator来合成1分钟bar就会有问题,因为20:59:00的那个tick既不属于上一交易日的1分钟bar(15:59)的,也不属于21:00的那一个1分钟bar,当然就只能够孤独地自成一个1bar啦!由此带来的问题是21:00的那一个1分钟bar的开盘价和成交量(这个成交量可能是很大)都可能是错了。
当然由此导致的5分钟、10分钟、15分钟、30分钟乃至1日的bar都可能是有问题的,因为它们都是1分钟bar合成的。
你现在用BarGenerator没有办法合成90分钟K线,不信你试试看!挺搞笑的一个问题!
天下苦此BarGenerator久矣!
jingsiaosing wrote:
一个类似的问题:开盘第一个tick的时间戳是20:59:00,第二个tick的时间戳是21:00:00, 他俩的minute不一样,所以在收到第二个tick的时候就会推送bar,bar的时间戳是20:59:00,是这样吗?
这也是也个问题,实盘中每个合约都会有集合竞价时段,这时候采用自带的BarGenerator来合成1分钟bar就会有问题,因为20:59:00的那个tick既不属于上一交易日的1分钟bar(15:59)的,也不属于21:00的那一个1分钟bar,当然就只能够孤独地自成一个1bar啦!由此带来的问题是21:00的那一个1分钟bar的开盘价和成交量(这个成交量可能是很大)都可能是错了。
当然由此导致的5分钟、10分钟、15分钟、30分钟乃至1日的bar都可能是有问题的,因为它们都是1分钟bar合成的。
解决方法:
wangjiancc wrote:
老师您好!
我的版本是2.1.9, 在 类 OrderItem 中有一个引用错误, self.orders : Dict[int,Dict[str,Order]] = {} # {ix:{orderid:order}}
这个Order 是引用那个对象,谢谢!
好久没有升级,我还不知道,这两天我升级下,看看是什么问题。
其实临时K线是每个tick都会变化的,岂止是1分钟!
1、目前的BarGenerator,如果你生成N分钟的K线,是等到完整的window_bar生成之后才执行on_Nmin_bar()之类的。缺少执行临时K线的机制。
2、其实这样也有好处,那就是在on_Nmin_bar()里计算产生的交易信号是稳定的,因为K线已经走完,不会发生变化了。
3、可是坏处也很明显,有时候一根巨大的临时K线会让你的交易有浮盈变成浮亏,可是你的策略会无动于衷,不动作!
4、那么你会说临时K线好,其实也不然!如果你依据临时K线计算产生交易信号,会出现频繁的信号忽闪问题,就是临时K线刚K开始就出现开仓信号,于是你的策略立即开仓了,可是之后的行情使得开仓信号又消失了,怎么办?你还要考虑把已经开了的仓位平掉,如此反复,光是手续费你都受不了!
所以:对临时K线的使用要有利弊分析,通盘考虑,不是一个扩展那么简单的!
不需要修改ArrayManager,与它无关,需要扩展BarGenerator的update_bar(),使之,
应该是在策略里面增加一个def on_temp_bar(self,bar:BarData):这样的推送接口,
当每次执行on_tick执行合成bar,判断bar是是否已经完成,来决定是执行on_temp_bar()还是on_bar()。
小天下 wrote:
也就是说,我同事使用5min,15min,30min在同一个策略中的时候,比如在10:08分,其实我能看到5min中的最后价格是10:00-10:04:59的价格,而15分钟,只能看到9:45-9;59:59秒的价格,而30min只能看到9:30-9:59:59秒的价格,就是只出现不再变化的K线,而不会出现临时K线?这样理解对么?所以如果需要临时k,就需要自己去改这个BarGenerator,大神这样理解 对么?
非常正确!
呵呵,两个错误:
1、rb888是米筐构造的一个前复权的螺纹期货合约,实际是不存在的,所以无法获得它的合约信息,因此无法获取它的交易时间段信息。而我这个RBreaker策略是必须使用交易时间段信息,所以出错!
2、你的K线周期设置为d,那么没有分钟数据,每次只有一个完整的日K先数据,还谈什么日内的上下突破?下载的数据必须为1m 。
换成rb2105.SHFE,K线周期设置为1m,把开始和结束日期改短些,再试试。
谢谢管理员!
是的,这么设计非常合理,否则在初始化和启动之间就会出现K线数据的缺失。
明白道理就不会觉得奇怪,而且对CTA策略的运行机制理解的更加透彻!
最近编写好了自己的CTA策略,上线运行,发现一个奇怪的现象:
1、设置好策略
2、初始化策略
3、运行策略
策略已经运行起来,一切都表现的正常——可以开仓、平仓。
可是当我想把策略停止下来,我发现交易停止了,可是on_bar()函数中的一些调试信息(为了观察策略的活动而增加的)仍然还在继续工作!
怪了,明明策略研究停止了的,为什么on_bar()函数仍然在执行?
原来策略中涉及到的合约与CTA策略是被添加到在CtaEngine中的symbol_strategy_map字典中了,而消息EVENT_TICK和CtaEngine的process_tick_event()被注册到消息引擎中,这样子只要接口接受到tick数据就会调用CtaEngine的process_tick_event()。
class CtaEngine(BaseEngine):
...
...
def init_engine(self):
self.init_rqdata()
self.load_strategy_class()
self.load_strategy_setting()
self.load_strategy_data()
self.register_event()
self.write_log("CTA策略引擎初始化成功")
def register_event(self):
""""""
self.event_engine.register(EVENT_TICK, self.process_tick_event)
self.event_engine.register(EVENT_ORDER, self.process_order_event)
self.event_engine.register(EVENT_TRADE, self.process_trade_event)
self.event_engine.register(EVENT_POSITION, self.process_position_event)
def process_tick_event(self, event: Event):
""""""
tick = event.data
strategies = self.symbol_strategy_map[tick.vt_symbol]
if not strategies:
return
self.check_stop_order(tick)
for strategy in strategies:
if strategy.inited:
self.call_strategy_func(strategy, strategy.on_tick, tick)
而CtaEngine的process_tick_event()中使用tick的vt_symbol找到symbol_strategy_map字典中对应所有策略,然后把tick逐个推送给策略的on_tick()函数,而这里只是判断每个策略的状态是否为inited==True。
如果说策略已经初始化了,那么不管是否被主动停止(trading==False),策略的on_tick()函数都会被执行!进而策略的on_bar()也会被执行,只是所有的交易函数均不会执行而已。
这样对停止策略的处理是否有点文不对题?既然已经停止策略,就应该把它停止下来,可是实际的情况是策略处理交易动作被限制之外,其他的处理逻辑和流程仍然再执行,并没有停止下来!
下面是CtaTemplate类中的几个交易相关函数的代码,其中就有策略的trading状态的限制条件:
def send_order(
self,
direction: Direction,
offset: Offset,
price: float,
volume: float,
stop: bool = False,
lock: bool = False
):
"""
Send a new order.
"""
if self.trading:
vt_orderids = self.cta_engine.send_order(
self, direction, offset, price, volume, stop, lock
)
return vt_orderids
else:
return []
def cancel_order(self, vt_orderid: str):
"""
Cancel an existing order.
"""
if self.trading:
self.cta_engine.cancel_order(self, vt_orderid)
def cancel_all(self):
"""
Cancel all orders sent by strategy.
"""
if self.trading:
self.cta_engine.cancel_all(self)
没有那么多一劳永逸的事情。
不过还是有一些更好的方法的,联合rqdatac的一些接口,可以做到许多意想不到的功能的:https://www.vnpy.com/forum/topic/4064-ni-de-kxian-ying-gai-shi-que-ding-de-ke-shi-ji-shang-que-bu-shi
你的这个函数离的实现是什么?5分钟K线是任何创建的?不交代清楚无法判断问题的!
def init__ (
self,
cta engine: Any ,
strategy- name: str ,
vt_ symboL: str ,
setting: dict,
):...
level999 wrote:
楼主,添加启动错误,请分析下什么原因啊
把这一句的
import vnpy.app.cta_strategy.base import EngineType # hxxjava add
改成
from vnpy.app.cta_strategy.base import EngineType # hxxjava add
就可以了。
黄裳 wrote:
感谢回复,我知道这个不难。只是有没有必要使用这种数据,如果使用的话,计算出来的指标或许会有反复,反而麻烦。
类比文华财经之类的软件,在on_bar()中使用1分钟bar,或者在on_5min_bar()中使用5分钟bar的话,这个叫收盘价模式。
而临时的bar则随tick而改变,属于非收盘价模式。
二者的区别是:收盘价模式下采用bar计算的指标信号是不会出现信号忽闪,而非收盘价模式采用bar计算的指标信号是会出现信号忽闪的,需要配合更高层的交易控制逻辑,必然信号出现多长时间算是信号确认。
例如:
非收盘价模式采用bar计算指标信号,确认入场信号10秒,确认离场信号5秒。
入场信号出现,策略下单了,可是3秒后又消失了,那么策略应该自带把之前下单的仓位平掉。
假如你持有仓位,离场场信号出现,策略立即平仓,可是2秒后又消失了,那么策略应该自带把之前平仓的仓位再拿回来。
由此可见非收盘价模式对价格的变化更为快速,但是要求对交易的控制更为复杂,不是实现了临时K线就万事大吉了!
黄裳 wrote:
也就是说,想要得到随时更新的5分钟线,30分钟线,就要从新写自己的BarGenerator,非常感谢
是的,就要重新写自己的BarGenerator。
你所说的随时更新的5分钟线,30分钟线其实是临时K线,而目前的BarGenerator没有直接提供你要的临时K线机制。
不过你可以扩展一个BarGenerator类,实现一个属性或者方法,如gen_temp_bar()和temp_bar(),具体办法:
def gen_temp_bar(self)
self.temp_bar = self.window_bar与self.bar的合成
当然这只是伪代码,自己实现下,应该不难。
def temp_bar(self)
return self.temp_bar
其中gen_temp_bar()需要在策略的on_tick()的函数中最后被执行,
def on_tick(self, tick: TickData):
"""
Callback of new tick data update.
"""
self.bg.update_tick(tick)
self.bg.gen_temp_bar()
这样你就可以得到window_bar的临时K线了。