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掉所有需求