針對VNPY的軟件bugs的修改總結(jié)

針對VNPY的軟件bugs的修改總結(jié)

前言

本人fork了VNPY的2.1.7版本,但是為了別人能夠安裝和使用官方的版本饿肺,所以取名叫howtrader, 意思就是如何Trader,如何成為一個quant或者trader。

但是在使用和測試的過程中匿又,發(fā)現(xiàn)針對幣安的api部分,有不少的bug進(jìn)行修改〗ㄌ悖現(xiàn)將部分的修改總結(jié)一下碌更。

bugs分析和修復(fù)過程

  1. k先部分,VNPY Trader是根據(jù)tick的數(shù)據(jù)來合成分鐘的K線洞慎,然后再講分鐘的K線合成更高界別的K線數(shù)據(jù)痛单。但是幣安的api他們推送的ticker數(shù)據(jù)是滾動24小時的ticker數(shù)據(jù),成交的價格和量都是過去24小時的數(shù)據(jù)劲腿,數(shù)據(jù)格式如下:
 {
 "e": "24hrTicker",  // 事件類型
 "E": 123456789,     // 事件時間
 "s": "BNBBTC",      // 交易對
 "p": "0.0015",      // 24小時價格變化
 "P": "250.00",      // 24小時價格變化(百分比)
 "w": "0.0018",      // 平均價格
 "x": "0.0009",      // 整整24小時之前旭绒,向前數(shù)的最后一次成交價格
 "c": "0.0025",      // 最新成交價格
 "Q": "10",          // 最新成交交易的成交量
 "b": "0.0024",      // 目前最高買單價
 "B": "10",          // 目前最高買單價的掛單量
 "a": "0.0026",      // 目前最低賣單價
 "A": "100",         // 目前最低賣單價的掛單量
 "o": "0.0010",      // 整整24小時前,向后數(shù)的第一次成交價格
 "h": "0.0025",      // 24小時內(nèi)最高成交價
 "l": "0.0010",      // 24小時內(nèi)最低成交加
 "v": "10000",       // 24小時內(nèi)成交量
 "q": "18",          // 24小時內(nèi)成交額
 "O": 0,             // 統(tǒng)計開始時間
 "C": 86400000,      // 統(tǒng)計結(jié)束時間
 "F": 0,             // 24小時內(nèi)第一筆成交交易ID
 "L": 18150,         // 24小時內(nèi)最后一筆成交交易ID
 "n": 18151          // 24小時內(nèi)成交數(shù)
}

根據(jù)這樣的ticker數(shù)據(jù)處理焦人,實際上得不到分鐘的數(shù)據(jù)的挥吵。所以需要訂閱分鐘的數(shù)據(jù),然后拿到分鐘的數(shù)據(jù)進(jìn)行合成花椭。

  1. vnpy的分鐘合成小時數(shù)據(jù)實際上它是慢了一分鐘的的忽匈,我們看下它合成的邏輯
def update_bar(self, bar: BarData) -> None:
        """
        Update 1 minute bar into generator
        """
        # If not inited, creaate window bar object
        if not self.window_bar:
            # Generate timestamp for bar data
            if self.interval == Interval.MINUTE:
                dt = bar.datetime.replace(second=0, microsecond=0)
            else:
                dt = bar.datetime.replace(minute=0, second=0, microsecond=0)

            self.window_bar = BarData(
                symbol=bar.symbol,
                exchange=bar.exchange,
                datetime=dt,
                gateway_name=bar.gateway_name,
                open_price=bar.open_price,
                high_price=bar.high_price,
                low_price=bar.low_price
            )
        # Otherwise, update high/low price into window bar
        else:
            self.window_bar.high_price = max(
                self.window_bar.high_price, bar.high_price)
            self.window_bar.low_price = min(
                self.window_bar.low_price, bar.low_price)

        # Update close price/volume into window bar
        self.window_bar.close_price = bar.close_price
        self.window_bar.volume += int(bar.volume)
        self.window_bar.open_interest = bar.open_interest

        # Check if window bar completed
        finished = False

        if self.interval == Interval.MINUTE:
            # x-minute bar
            if not (bar.datetime.minute + 1) % self.window:
                finished = True
        elif self.interval == Interval.HOUR:
            if self.last_bar and bar.datetime.hour != self.last_bar.datetime.hour:
                # 1-hour bar
                if self.window == 1:
                    finished = True
                # x-hour bar
                else:
                    self.interval_count += 1

                    if not self.interval_count % self.window:
                        finished = True
                        self.interval_count = 0

        if finished:
            self.on_window_bar(self.window_bar)
            self.window_bar = None

        # Cache last bar object
        self.last_bar = bar

主要看這個代碼, 它是根據(jù)當(dāng)前小時和上一個小時數(shù)據(jù)不同的時候,就是一小時的數(shù)據(jù)矿辽,但是幣安的K線數(shù)的時間是開始的時間的丹允,所以一小時的結(jié)束的時候郭厌,實際上是59分鐘,也就是59分鐘的時候這個小時就走完了雕蔽,另外成交量是可以float的類型折柠,它強制轉(zhuǎn)成int的類型,也是不對的批狐。

if self.interval == Interval.MINUTE:
            # x-minute bar
        if not (bar.datetime.minute + 1) % self.window:
                finished = True
elif self.interval == Interval.HOUR:
            if self.last_bar and bar.datetime.hour != self.last_bar.datetime.hour:
                # 1-hour bar
                if self.window == 1:
                    finished = True
                # x-hour bar
                else:
                    self.interval_count += 1

                    if not self.interval_count % self.window:
                        finished = True
                        self.interval_count = 0

正確的做法是:

if self.interval == Interval.MINUTE:
            # x-minute bar
            if not (bar.datetime.minute + 1) % self.window:
                finished = True
elif self.interval == Interval.HOUR:
            # if self.last_bar and bar.datetime.hour != self.last_bar.datetime.hour: # vnpy的判斷條件
            if (bar.datetime.minute == 59 and bar.interval == Interval.MINUTE) or (self.last_bar and bar.datetime.hour != self.last_bar.datetime.hour and bar.interval == Interval.HOUR):
                # if the bar is one minute, then the 59minute is the last one bar for one hour.
                # 1-hour bar
                if self.window == 1:
                    finished = True
                # x-hour bar
                else:
                    self.interval_count += 1

                    if not self.interval_count % self.window:
                        finished = True
                        self.interval_count = 0
  1. 關(guān)于訂單的on_trade的推送
    on_trade事件的推送非常重要液走,如果on_trade的事件沒有收到,那么策略的倉位數(shù)據(jù)pos是計算錯誤的贾陷。

VNPY的on_trade更新只來自服務(wù)器的推送缘眶,如果不湊巧,某個時間你剛好成交了髓废,但是由于你的websocket斷開巷懈,你沒有收到服務(wù)器推送的on_trade的更新,導(dǎo)致你的策略的pos計算錯誤慌洪。

所以解決問題的方法是顶燕,我們更過監(jiān)聽on_trade的方法,然后計算每次訂單的成交量來計算on_trade, 同時我們會在主引擎那里冈爹,定時去查詢掛單時間比較長的訂單涌攻,防止由于服務(wù)器的斷開導(dǎo)致我們的訂單狀態(tài)更新沒有收到。

  1. 關(guān)于推送的on_position
    同樣on_position是我們做合約非常重要的數(shù)據(jù)频伤,我們可能成交了恳谎,但是position的數(shù)據(jù)由于websocket沒有及時的推送,另外VNPY查詢的on_position如果通過rest api查詢的話憋肖,實際上它只推送position不為零的數(shù)據(jù)因痛,這個也不太合理,合理的做法是我們也應(yīng)該推送訂閱行情的倉位數(shù)據(jù)岸更,這樣如果我們的平倉的時候鸵膏,我們的倉位也是為零的,但是也應(yīng)該推送給我們怎炊,這樣我們才能監(jiān)聽到我們的具體倉位的變化谭企。

代碼更新

具體查看github的代碼

VNPY學(xué)習(xí)資料

課程封面.png

請參考網(wǎng)易云課堂的課程視頻

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市评肆,隨后出現(xiàn)的幾起案子债查,更是在濱河造成了極大的恐慌,老刑警劉巖糟港,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件攀操,死亡現(xiàn)場離奇詭異,居然都是意外死亡秸抚,警方通過查閱死者的電腦和手機速和,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門歹垫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人颠放,你說我怎么就攤上這事排惨。” “怎么了碰凶?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵暮芭,是天一觀的道長。 經(jīng)常有香客問我欲低,道長辕宏,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任砾莱,我火速辦了婚禮瑞筐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘腊瑟。我一直安慰自己聚假,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布闰非。 她就那樣靜靜地躺著膘格,像睡著了一般。 火紅的嫁衣襯著肌膚如雪财松。 梳的紋絲不亂的頭發(fā)上瘪贱,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機與錄音游岳,去河邊找鬼政敢。 笑死其徙,一個胖子當(dāng)著我的面吹牛胚迫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播唾那,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼访锻,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了闹获?” 一聲冷哼從身側(cè)響起期犬,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎避诽,沒想到半個月后龟虎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡沙庐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年鲤妥,在試婚紗的時候發(fā)現(xiàn)自己被綠了佳吞。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡棉安,死狀恐怖底扳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情贡耽,我是刑警寧澤衷模,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站蒲赂,受9級特大地震影響阱冶,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜滥嘴,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一熙揍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧氏涩,春花似錦届囚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至饺汹,卻和暖如春蛔添,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背兜辞。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工迎瞧, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人逸吵。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓凶硅,卻偏偏與公主長得像,于是被迫代替她去往敵國和親扫皱。 傳聞我的和親對象是個殘疾皇子足绅,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容