構建區塊鏈量化交易系統(一)

Yaser Abu-Mostafa在公開課說工程師,喝着咖啡等待機器運算出合理的結果,然後就完成了任務,坐等顧客付錢,這也是我寫這篇文章以及代碼的原因。

本文結構,暫時分爲,三個部分

一,基礎理論以及代碼基礎

二,機器學習在上的基礎應用(Tensorflow + Python去做)

三,系統可靠性加固

代碼在https://github.com/hzm1313/yc,代碼冗餘了其他一些東西,後面會用JAVA9的模塊特性把模塊給分出來,火幣網的接口封裝了WS,和restful,槓桿未封裝

平臺選擇爲火幣網,說起來是因爲以前火幣網不用翻牆,可惜現在也要翻了,所以翻牆是必備的,可以用SSTAP去連接SSR結點,會將TCP,UDP連接也進行轉發,原生的用IDEA調試總是有問題

點擊我去搭建SSR  SSTAP下載鏈接,已經不維護了,可以自己選其他的

量化交易定義

根據深圳交易所對量化交易的研究可知,量化交易是指投資者利用計算機技術、金融工程建模等手段將自己的金融操作方式,用很明確的方式去定義和描述,用以協助投資者進行投資決策,並且嚴格的按照所設定的規則去執行交易策略(買、賣)的交易方式。按照數學模型的理念和對計算機技術的利用方式,量化交易方式可以進一步細分爲自動化交易(Automatic Trading)、數量化投資(Quantitative Investment)、程序化交易(Program Trading)、算法交易(Algorithm Trading)、以及高頻交易(High Frequency Trading)

自動化交易

指將技術分析投資方式固化成計算機可以理解的模型、技術指標,計算機程序根據市場變化自動生成投資決策並付諸執行的交易方式。簡而言之,自動化交易是技術分析投資方式的自動化。自動化交易可以避免投資人的心理變化和情緒波動,嚴格執行既定策略,是最基本的量化交易方式,在外匯交易和期貨交易領域應用很廣。

程序化交易

是從美國七十年代的證券市場上的系統化交易發展演變而來的,是伴隨着股指期貨與現貨市場套利交易而興起的數量化交易方式。紐約證券交易所(NYSE)把程序化交易定義爲:Program trading encompasses a wide range of portfolio-trading strategies involving the purchase or sale of a basket of at least 15 stocks with a total value of $1 million or more.即任何含有標普500指數15只股票以上,其價值100萬美元以上的交易,屬於程序化交易。紐約證券交易所的定義主要突出的是交易規模和集中性。程序化交易發展到今天,其含義已經遠遠超過了紐約證券交易所當初的定義。國泰君安證券對程序化交易給出了一個更爲市場化的定義:根據一定的交易規模和規則生成買賣信號,由計算機自動執行買賣指令的交易過程。簡單的說,就是利用計算機程序來控制買進賣出的事蹟並自動執行。在這個定義中,突出的是交易模型、計算機程序對交易的重要性。隨着量化技術的深入發展,程序化交易和算法交易的界限逐漸模糊,有些市場使用高頻交易描述流行的量化交易方式。

高頻交易

源於程序化交易和做市商機制,是指透過極高速的超級電腦分析高頻交易數據中的價格變化模式,並且利用這些價格變化模式獲利,通常高頻交易利用服務器的地理位置優勢(Co-location),在相對更快的時間內獲得市場行情和執行大量交易指令,從而取得普通交易方式難以獲得的利潤空間。近年來,除了信息技術是的交易速度不斷加快之外,交易平臺日趨多元化也使得高頻交易成爲可能。

數量化交易

通過研究基本面去做,做爬蟲爬信息去做

算法交易

更好的價格買入,因爲你作爲資金量較大的用戶,買入,市場印象較大

算法交易,數量化交易(研究基本面)我研究不多,因爲概念上對於大多數人並不是一個很優秀的實施概念,所以就不展開了,要是有什麼好的文章或者思路也可以分享給我,感謝

自動化交易,高頻交易,程序化交易是在本系統構建範圍之內

代碼構建思路

現在我寫了2個策略

策略A,1分鐘線上下跌30次,買入,上漲或者下跌0.005%賣出

策略B,網格策略,上漲5%,10%,15%,分別買入總價的30%,30%,40%,下跌反之,基準價,我開上帝模式,選了要給比較好的基準價

這是自動化交易

策略A進一步,1分鐘下跌(N)次,選擇一個比較優秀的下跌次數以及回測範圍,去回測,動態的生成策略

策略B進一步,網格策略,上漲N%,買入總量/當前量的N%,去回測,動態生成優秀的策略

高頻交易

比如說現在幣安,火幣網,幣安下跌,火幣網上漲,這個時候我擁有火幣網的幣,是否賣出,當然賣,爲什麼?因爲根據歷史回測來看,幣安作爲全球第二的市場,反應幣火幣網快。也可以參考CEX,這種可以對沖的市場,現在有自動搬磚的軟件了,我也就重點實現了

火幣網API,實現有RESTFUL,和websocket2種類型,websocket接口有行情接口,restful接口有行情和交易接口,但是restful行情接口有不好的地方,速度和歷史數據沒有websocket的久遠

基於上面2個策略,我做了回測,效果都不是很好,因爲現在我選取之前的時間段是單邊下跌時間,所以回測結果基本上都是虧損,下面是代碼代碼放在我的GIT

 @Test
    public void baseStrategy() {
        //策略1
        //連續下跌30分鐘線,買入,直到,高於成本價0.5%,賣出,否則一直持有,手續費爲0.4%,如果下跌超過1%,,無條件賣出
        //讀取數據
       /* List<HuobiDetailVO> huobiDetailVOList  = HuoBiApiUtils.importToFile("E:\\虛擬貨幣\\測試數據\\test_1min.xlsx");*/
        List<List<String>> lists = ExceUtil.importFile(new File("E:\\虛擬貨幣\\測試數據\\test.xlsx"));
        if (false) {
            List<Map<String, String>> mapList = new ArrayList<>();
            for (int fallTraigger = 1; fallTraigger < 30; fallTraigger++) {
                //1W刀本金
                BigDecimal amount = new BigDecimal("10000");
                BigDecimal holdPrice = new BigDecimal("0");
                BigDecimal holdNum = new BigDecimal("0");
                BigDecimal basePrice = new BigDecimal(lists.get(1).get(3));
                BigDecimal open = new BigDecimal(lists.get(1).get(2));
                BigDecimal close = new BigDecimal(lists.get(1).get(3));
                BigDecimal high = new BigDecimal(lists.get(1).get(4));
                BigDecimal low = new BigDecimal(lists.get(1).get(5));
                //觸發的賣出價格
                BigDecimal sellLowPrice = new BigDecimal(lists.get(1).get(3)).multiply(new BigDecimal("0.99"));
                BigDecimal sellHighPrice = new BigDecimal(lists.get(1).get(3)).multiply(new BigDecimal("1.005"));
                int falNum = 0;
                for (int i = 2; i < lists.size(); i++) {
                    open = new BigDecimal(lists.get(i).get(2));
                    close = new BigDecimal(lists.get(i).get(3));
                    high = new BigDecimal(lists.get(i).get(4));
                    low = new BigDecimal(lists.get(i).get(5));
                    if (holdNum.compareTo(new BigDecimal("0")) == 0) {
                        //持有本金,買入等待狀態
                        if (close.compareTo(basePrice) < 0) {
                            falNum++;
                        } else {
                            falNum = 0;
                        }
                        if (falNum >= fallTraigger) {
                            //買入手續費
                            amount = amount.multiply(new BigDecimal("0.998"));
                            holdPrice = close;
                            holdNum = amount.divide(holdPrice, 10, BigDecimal.ROUND_DOWN);
                            amount = new BigDecimal("0");
                            //System.out.println("買入價:" + holdPrice + " 買入數量:" + holdNum + " 總價值:" + holdNum.multiply(holdPrice) + " 剩餘錢:" + amount.toString());
                            sellLowPrice = new BigDecimal(lists.get(i).get(3)).multiply(new BigDecimal("0.994"));
                            sellHighPrice = new BigDecimal(lists.get(i).get(3)).multiply(new BigDecimal("1.006"));
                            falNum = 0;
                        }
                    } else {
                        //持有幣,賣出等待狀態\
                        //低於1.05賣出
                        if (close.compareTo(sellLowPrice) < 0 || close.compareTo(sellHighPrice) > 0) {
                            holdPrice = close;
                            amount = holdNum.multiply(holdPrice).multiply(new BigDecimal("0.998"));
                            //System.out.println("賣出價:" + holdPrice + " 買出數量:" + holdNum +" 稅後錢:"+amount);
                            holdNum = new BigDecimal("0");
                        }
                    }
                    basePrice = close;
                }
                if (holdNum.compareTo(new BigDecimal("0")) > 0) {
                    //強行賣出
                    amount = holdNum.multiply(holdPrice).multiply(new BigDecimal("0.998"));
                }
                System.out.println("fallTraigger:" + fallTraigger + "  resultPrice:" + amount.toString());
                Map map = new HashMap<String, String>();
                map.put("fallTraigger", fallTraigger);
                map.put("resultPrice", amount.toString());
                mapList.add(map);
            }
            mapList.sort((o1, o2) -> o1.get("resultPrice").compareTo(o1.get("resultPrice")));
            mapList.forEach(obj -> {
                System.out.println(String.valueOf(obj.get("fallTraigger")) + "===" + obj.get("resultPrice"));
            });
        }
        //策略2,網格策略
        //爲了拿一個好看的回測結果,我就上帝模式來一波,數據是自己去取的一個平均值
        //步長5%,上漲5%,賣出30%,上漲10%,賣出30%,上漲15%,賣出40%,
        //下跌同理,簡化了很多東西
        for(int stepType=1;stepType<4;stepType++){
            BigDecimal stepLength = new BigDecimal("0.5").multiply(new BigDecimal(stepType));
            BigDecimal basePrice = new BigDecimal("8000.5243315970");
            //1W刀本金
            BigDecimal amount = new BigDecimal("10000");
            BigDecimal holdNum = new BigDecimal("0");
            BigDecimal tradePrice = new BigDecimal("0");
            BigDecimal close = new BigDecimal(lists.get(1).get(3));
            BigDecimal percent3 = new BigDecimal("0.30");
            BigDecimal percent4 = new BigDecimal("0.40");
            BigDecimal opPrice =  null;
            ReseauStratge trade[] = {new ReseauStratge(amount.multiply(percent3)),new ReseauStratge(amount.multiply(percent3)),new ReseauStratge(amount.multiply(percent4))};
            for (int perIndex = 2; perIndex < lists.size(); perIndex++) {
                close = new BigDecimal(lists.get(perIndex).get(3));
                //買入/賣出
                //對於每個階段的資金來說,只有,買入,賣出2種狀態
                for(int buyPercentNum=0;buyPercentNum<trade.length;buyPercentNum++){
                    opPrice = new BigDecimal(basePrice.toString());
                    BigDecimal step = new BigDecimal("1.00");
                    if(trade[buyPercentNum].getCanBuy()) {
                        //買入
                        for(int muNum = 1; muNum<=buyPercentNum+1;muNum++){
                            step = step.divide(stepLength,10,BigDecimal.ROUND_FLOOR);
                        }
                        opPrice = opPrice.multiply(step);
                        if(close.compareTo(opPrice)<=0) {
                            trade[buyPercentNum].setTradePrice(close);
                            trade[buyPercentNum].setTradeNum(new BigDecimal(trade[buyPercentNum].getHoldAmount().divide(close,10,BigDecimal.ROUND_FLOOR).toString()));
                            trade[buyPercentNum].setHoldNum(trade[buyPercentNum].getTradeNum());
                            trade[buyPercentNum].setTradeAmount(trade[buyPercentNum].getTradeNum().multiply(trade[buyPercentNum].getTradePrice()));
                            trade[buyPercentNum].setHoldAmount(trade[buyPercentNum].getHoldAmount().subtract(trade[buyPercentNum].getTradeAmount()));
                            trade[buyPercentNum].setCanBuy(false);
                            holdNum = holdNum.add(trade[buyPercentNum].getHoldNum());
                            amount = amount.subtract(trade[buyPercentNum].getTradeAmount());
                           // System.out.println("買入"+"holdNum:" + holdNum + "  resultPrice:" + amount.toString()+"總價值" + amount.add(holdNum.multiply(close)));
                        }
                    } else {
                        //賣出
                        for(int muNum = 1; muNum<=buyPercentNum+1;muNum++){
                            step = step.subtract(stepLength);
                        }
                        opPrice = opPrice.multiply(step);
                        if(close.compareTo(opPrice) >= 0) {
                            trade[buyPercentNum].setTradePrice(close);
                            trade[buyPercentNum].setTradeAmount(trade[buyPercentNum].getHoldNum().multiply(trade[buyPercentNum].getTradePrice()));
                            trade[buyPercentNum].setHoldAmount(trade[buyPercentNum].getHoldAmount().add(trade[buyPercentNum].getTradeAmount()));
                            trade[buyPercentNum].setTradeNum(trade[buyPercentNum].getHoldNum());
                            trade[buyPercentNum].setHoldNum(new BigDecimal("0"));
                            trade[buyPercentNum].setCanBuy(true);
                            amount = amount.add(trade[buyPercentNum].getTradeAmount());
                            holdNum = holdNum.subtract(trade[buyPercentNum].getTradeNum());
                          //  System.out.println("賣出"+"holdNum:" + holdNum + "  resultPrice:" + amount.toString()+"總價值" + amount.add(holdNum.multiply(close)));
                        }
                    }
                }
            }
            System.out.println("holdNum:" + holdNum + "  resultPrice:" + amount.toString() +"總價值" + amount.add(holdNum.multiply(close)));
        }
    }

這就是交易的基礎模型,價值還是有價值的,畢竟還是掙錢的,掙的特別少,1W刀,100刀-700刀,幅度太坑,2個月的回測,17年12月到18年的2月

holdNum:0E-10  resultPrice:10746.2908951017280000000000000000總價值10746.2908951017280000000000000000
holdNum:0E-10  resultPrice:10548.5590028459460000000000000000總價值10548.5590028459460000000000000000

holdNum:0E-10  resultPrice:10139.7957370829220000000000000000總價值10139.7957370829220000000000000000

能不能掙錢,就看steplength以及basePrice的設置

現在是定死的價格,所以如果做無限動態的化,可以考慮每天/每小時/重新設置basePrice,看自己的需求

這是2種基礎的交易模型

然後這個時候需要引出風控了,因爲在回測的時候,模型成功率在某段時間不高的時候,所以需要終止模型的運轉,發出郵件通知自己

高頻交易

(BitMex/Biance)與火幣做對比

----代碼暫時未寫,不想爬蟲,不想封接口了,都TM苦力活,要吐了,後面補進來---

交易模型已經構造完畢

交易系統,穩定,快速,易更改,可監控(其實redis一套可以弄完,不過是爲了學習,會採取自己接觸比較少的東西去做)

監控選用 Promethus,然後拉取數據,做可視化

穩定:代碼看自己了

快速:併發的走起

更改:數據庫配置的走起,然後RabbitMQ做消息隊列推

存儲: redis持久化搞

現在很多海外服務,所以用spring cloud,搭建微服務,做服務調用

java + python交互,做機器學習模型結果的交互

這是我整個系統的構造思路,代碼會在git裏面也會一步一步OVER掉所有需求

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章