日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

说说海龟交易法则的基本原理,如何实现海龟交易策略?

發(fā)布時間:2023/12/8 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 说说海龟交易法则的基本原理,如何实现海龟交易策略? 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

原文地址:https://www.fmz.cn/digest-topic/8978
什么是海龜策略?
幾乎所有的寬客(Quant)都聽說過海龜交易策略,該策略以海龜交易法則為核心。海龜交易法則,起源于八十年代的美國,是一套簡單有效的交易法則。這個法則以及使用這個法則的人的故事被寫成了一本書——《海龜交易法則》,這是一本入門量化投資的經(jīng)典書籍。

股票證券的程序化、量化交易以前門檻可不低,以前軟件支持少,賬戶開戶門檻極高。FMZ.CN(國內(nèi)站)支持富途證券、中泰XTP,開通了富途證券就可以很方便的做程序化模擬盤、實盤測試。本篇我們就一起學(xué)習(xí)設(shè)計一個股票版本的多品種海龜交易策略,初期我們主要基于回測系統(tǒng)進行設(shè)計、研究,慢慢的擴展至富途證券的模擬盤(模擬賬戶)。

策略設(shè)計:
策略架構(gòu)我們參考http://FMZ.CN上開源的「商品期貨多品種海龜策略」。和商品期貨版本一樣,我們設(shè)計一個海龜交易邏輯管理對象的構(gòu)造函數(shù)TTManager。構(gòu)造的對象(obj)用來操作、管理每個股票的海龜交易邏輯的執(zhí)行。

```javascriptvar TTManager = {New: function(needRestore, symbol, initBalance, keepBalance, riskRatio, atrLen, enterPeriodA, leavePeriodA, enterPeriodB, leavePeriodB, useFilter,multiplierN, multiplierS, maxLots) {// subscribevar symbolDetail = _C(exchange.SetContractType, symbol)if (symbolDetail.VolumeMultiple == 0) {Log(symbolDetail)throw "股票合約信息異常"} else {Log("合約", symbolDetail.InstrumentName, "一手", symbolDetail.VolumeMultiple, "股, 最大下單量", symbolDetail.MaxLimitOrderVolume, ", 最小下單量", symbolDetail.VolumeMultiple)}var obj = {symbol: symbol,tradeSymbol: symbolDetail.InstrumentID,initBalance: initBalance,keepBalance: keepBalance,riskRatio: riskRatio,atrLen: atrLen,enterPeriodA: enterPeriodA,leavePeriodA: leavePeriodA,enterPeriodB: enterPeriodB,leavePeriodB: leavePeriodB,useFilter: useFilter,multiplierN: multiplierN,multiplierS: multiplierS}obj.maxLots = maxLotsobj.lastPrice = 0obj.symbolDetail = symbolDetailobj.status = {symbol: symbol,recordsLen: 0,vm: [],open: 0,cover: 0,st: 0,marketPosition: 0,lastPrice: 0,holdPrice: 0,holdAmount: 0,holdProfit: 0,switchCount: 0,N: 0,upLine: 0,downLine: 0,lastErr: "",lastErrTime: "",stopPrice: '',leavePrice: '',isTrading: false}... 股票市場和商品期貨市場又有些差別,下面我們來一起分析一下這些差別,然后對于策略進行具體的修改、設(shè)計。交易時間差別 我們需要單獨設(shè)計一個函數(shù),識別開盤休盤時間,如下函數(shù)設(shè)計,給構(gòu)造函數(shù)TTManager返回的對象obj增加方法:```javascript```javascript obj.newDate = function() {var timezone = 8 var offset_GMT = new Date().getTimezoneOffset() var nowDate = new Date().getTime() var targetDate = new Date(nowDate + offset_GMT * 60 * 1000 + timezone * 60 * 60 * 1000)return targetDate}obj.isSymbolTrading = function() {// 使用 newDate() 代替 new Date() 因為服務(wù)器時區(qū)問題var now = obj.newDate()var day = now.getDay()var hour = now.getHours()var minute = now.getMinutes()StatusMsg = "非交易時段"if (day === 0 || day === 6) {return false}if((hour == 9 && minute >= 30) || (hour == 11 && minute < 30) || (hour > 9 && hour < 11)) {// 9:30-11:30StatusMsg = "交易時段"return true } else if (hour >= 13 && hour < 15) {// 13:00-15:00StatusMsg = "交易時段"return true } return false } 交易方向的差別 商品期貨有開倉、平倉。股票只有買、賣,沒有開倉平倉。股票類似于現(xiàn)貨,但是也有持倉,買入的股票會在GetPosition函數(shù)獲取的持倉列表中顯示。需要我們對交易下單的部分做設(shè)計,增加函數(shù):```javascript obj.sell = function(e, contractType, lots, insDetail) {... }obj.buy = function(e, contractType, opAmount, insDetail) {... }

下單頭寸計算
商品期貨交易下單時是按照合約張數(shù)下單,一張合約根據(jù)其合約乘數(shù)代表一定量的商品(例如rb合約,一張代表10噸螺紋鋼)。股票雖說也是有按手計算的(根據(jù)板塊有的1手100股,有的500股,還有的200股)。但是下單的時候必須是股數(shù),并且要能被一手的股數(shù)整除。不能整除的會報錯。

這樣就需要對海龜交易法計算頭寸的部分做一定修改:

var atrs = TA.ATR(records, atrLen)var N = _N(atrs[atrs.length - 1], 4)var account = _C(exchange.GetAccount)var unit = parseInt((obj.initBalance-obj.keepBalance) * (obj.riskRatio / 100) / N / obj.symbolDetail.VolumeMultiple)var canOpen = parseInt((account.Balance-obj.keepBalance) / (lastPrice * 1.2) / obj.symbolDetail.VolumeMultiple)unit = Math.min(unit, canOpen)unit = unit * obj.symbolDetail.VolumeMultipleif (unit < obj.symbolDetail.VolumeMultiple) {obj.setLastError("可開 " + unit + " 手 無法開倉, " + (canOpen >= obj.symbolDetail.VolumeMultiple ? "風(fēng)控觸發(fā)" : "資金限制") + "。 可用: " + account.Balance)return}// 交易函數(shù)if (opCode == 2) {throw "股票不支持做空"}

策略注釋
為了方便理解策略代碼,我們對策略通篇注釋。

/*backtest start: 2016-05-01 00:00:00 end: 2022-02-19 23:59:00 period: 1d basePeriod: 1d exchanges: [{"eid":"Futures_XTP","currency":"STOCK","minFee":0}] args: [["Instruments","600519.SH,600690.SH,600006.SH,601328.SH,600887.SH,600121.SH,601633.SH"],["ATRLength",30],["EnterPeriodA",30],["LeavePeriodA",50],["EnterPeriodB",60],["LeavePeriodB",80],["KeepRatio",5]] */var SlideTick = 10 // 下單滑價點數(shù),設(shè)置10下買單時價格加10跳 var Interval = 1000 // 程序暫停毫秒數(shù)/* TTManager : 海龜交易邏輯對象的構(gòu)造函數(shù) 參數(shù):needRestore, symbol, initBalance, keepBalance, riskRatio, atrLen, enterPeriodA, leavePeriodA, enterPeriodB, leavePeriodB, useFilter, multiplierN, multiplierS, maxLots需要恢復(fù)持倉、交易品種代碼、初始資產(chǎn)、保留資產(chǎn)、風(fēng)險系數(shù)、ATR參數(shù)、入市周期A,離市周期A、入市周期B、離市周期B、是否使用入市過濾、加倉間隔(N的倍數(shù))、止損系數(shù)(N的倍數(shù))、最大加倉次數(shù) */ var TTManager = {New: function(needRestore, symbol, initBalance, keepBalance, riskRatio, atrLen, enterPeriodA, leavePeriodA, enterPeriodB, leavePeriodB, useFilter,multiplierN, multiplierS, maxLots) {// subscribevar symbolDetail = _C(exchange.SetContractType, symbol) // 切換合約代碼,合約代碼為symbol的值if (symbolDetail.VolumeMultiple == 0) { // SetContractType會返回切換的品種的一些信息,檢測返回的數(shù)據(jù)中的VolumeMultiple字段是否正常Log(symbolDetail)throw "股票合約信息異常"} else {Log("合約", symbolDetail.InstrumentName, "一手", symbolDetail.VolumeMultiple, "股, 最大下單量", symbolDetail.MaxLimitOrderVolume, ", 最小下單量", symbolDetail.VolumeMultiple) // 輸出相關(guān)信息}// 聲明當(dāng)前構(gòu)造函數(shù)TTManager返回的對象obj,該對象記錄每個海龜交易邏輯的相關(guān)信息,例如執(zhí)行的品種(股票代碼)、ATR參數(shù)、加倉、止損N值系數(shù)等var obj = {symbol: symbol,tradeSymbol: symbolDetail.InstrumentID,initBalance: initBalance,keepBalance: keepBalance,riskRatio: riskRatio,atrLen: atrLen,enterPeriodA: enterPeriodA,leavePeriodA: leavePeriodA,enterPeriodB: enterPeriodB,leavePeriodB: leavePeriodB,useFilter: useFilter,multiplierN: multiplierN,multiplierS: multiplierS}obj.maxLots = maxLotsobj.lastPrice = 0obj.symbolDetail = symbolDetailobj.status = {symbol: symbol,recordsLen: 0,vm: [],open: 0,cover: 0,st: 0,marketPosition: 0,lastPrice: 0,holdPrice: 0,holdAmount: 0,holdProfit: 0,switchCount: 0,N: 0,upLine: 0,downLine: 0,lastErr: "",lastErrTime: "",stopPrice: '',leavePrice: '',isTrading: false}// 用于記錄錯誤的函數(shù),記錄的信息會在狀態(tài)欄上顯示obj.setLastError = function(err) {if (typeof(err) === 'undefined' || err === '') {obj.status.lastErr = ""obj.status.lastErrTime = ""return}var t = new Date()obj.status.lastErr = errobj.status.lastErrTime = t.toLocaleString()}// 獲取指定股票代碼的持倉數(shù)據(jù)obj.getPosition = function(e, contractTypeName) {var allAmount = 0var allProfit = 0var allFrozen = 0var posMargin = 0var price = 0var direction = nullpositions = _C(e.GetPosition) // 根據(jù)參數(shù)e調(diào)用指定的交易所對象的獲取持倉函數(shù)GetPosition,e即代表一個配置的賬戶,e.GetPosition即代表獲取這個賬戶目前的持倉數(shù)據(jù)for (var i = 0; i < positions.length; i++) {// 遍歷持倉數(shù)據(jù),找到指定的股票if (positions[i].ContractType != contractTypeName) {continue}if (positions[i].Type == PD_LONG) {posMargin = positions[i].MarginLevelallAmount += positions[i].AmountallProfit += positions[i].ProfitallFrozen += positions[i].FrozenAmountprice = positions[i].Pricedirection = positions[i].Type}}if (allAmount === 0) {return null}return {MarginLevel: posMargin,FrozenAmount: allFrozen,Price: price,Amount: allAmount,Profit: allProfit,Type: direction,ContractType: contractTypeName,CanCoverAmount: allAmount - allFrozen}}// 獲取當(dāng)前時間對象obj.newDate = function() {var timezone = 8 var offset_GMT = new Date().getTimezoneOffset() var nowDate = new Date().getTime() var targetDate = new Date(nowDate + offset_GMT * 60 * 1000 + timezone * 60 * 60 * 1000)return targetDate}// 判斷是否開市obj.isSymbolTrading = function() {// 使用 newDate() 代替 new Date() 因為服務(wù)器時區(qū)問題var now = obj.newDate()var day = now.getDay()var hour = now.getHours()var minute = now.getMinutes()StatusMsg = "非交易時段"if (day === 0 || day === 6) {return false}if((hour == 9 && minute >= 30) || (hour == 11 && minute < 30) || (hour > 9 && hour < 11)) {// 9:30-11:30StatusMsg = "交易時段"return true } else if (hour >= 13 && hour < 15) {// 13:00-15:00StatusMsg = "交易時段"return true } return false }// 買入函數(shù)obj.buy = function(e, contractType, opAmount, insDetail) {var initPosition = obj.getPosition(e, contractType) // 獲取初始時的持倉var isFirst = truevar initAmount = initPosition ? initPosition.Amount : 0 // 設(shè)置初始持倉數(shù)量var positionNow = initPosition // 設(shè)置當(dāng)前持倉數(shù)據(jù)if(!IsVirtual() && opAmount % insDetail.LotSize != 0) { // 判斷需要交易的數(shù)量opAmount(股數(shù))是否符合整手?jǐn)?shù)throw "每手?jǐn)?shù)量不匹配"}while (true) {var needOpen = opAmountif (isFirst) {isFirst = false} else {Sleep(Interval*20)positionNow = obj.getPosition(e, contractType)if (positionNow) {needOpen = opAmount - (positionNow.Amount - initAmount)}} // 需要交易的量如果小于一手?jǐn)?shù)量,或者不符合整手?jǐn)?shù)跳出循環(huán)if (needOpen < insDetail.LotSize || (needOpen % insDetail.LotSize != 0 && !IsVirtual())) {break} var depth = _C(e.GetDepth)// 需要檢測是否漲跌停var amount = needOpene.SetDirection("buy")var orderId = e.Buy(depth.Asks[0].Price + (insDetail.PriceSpread * SlideTick), amount, contractType, 'Ask', depth.Asks[0])// CancelPendingOrderswhile (true) {Sleep(Interval*20)var orders = _C(e.GetOrders)if (orders.length === 0) {break}for (var j = 0; j < orders.length; j++) {e.CancelOrder(orders[j].Id)if (j < (orders.length - 1)) {Sleep(Interval*20)}}}}var ret = nullif (!positionNow) {return ret}ret = positionNowreturn ret}// 賣出函數(shù)obj.sell = function(e, contractType, lots, insDetail) {var initAmount = 0var firstLoop = trueif(!IsVirtual() && lots % insDetail.LotSize != 0) {throw "每手?jǐn)?shù)量不匹配"}while (true) {var n = 0var total = 0var positions = _C(e.GetPosition)var nowAmount = 0for (var i = 0; i < positions.length; i++) {if (positions[i].ContractType != contractType) {continue}nowAmount += positions[i].Amount}if (firstLoop) {initAmount = nowAmountfirstLoop = false}var amountChange = initAmount - nowAmountif (typeof(lots) == 'number' && amountChange >= lots) {break} for (var i = 0; i < positions.length; i++) {if (positions[i].ContractType != contractType) {continue}var amount = positions[i].Amountvar depthvar opAmount = 0var opPrice = 0if (positions[i].Type == PD_LONG) {depth = _C(e.GetDepth)// 需要檢測是否漲跌停opAmount = amountopPrice = depth.Bids[0].Price - (insDetail.PriceSpread * SlideTick)}if (typeof(lots) === 'number') {opAmount = Math.min(opAmount, lots - (initAmount - nowAmount))}if (opAmount > 0) {if (positions[i].Type == PD_LONG) {e.SetDirection("closebuy")e.Sell(opPrice, opAmount, contractType, "平倉", 'Bid', depth.Bids[0])}n++}// break to check alwaysif (typeof(lots) === 'number') {break}}if (n === 0) {break}while (true) {Sleep(Interval*20)var orders = _C(e.GetOrders)if (orders.length === 0) {break}for (var j = 0; j < orders.length; j++) {e.CancelOrder(orders[j].Id)if (j < (orders.length - 1)) {Sleep(Interval*20)}}}}}// 恢復(fù)控制對象數(shù)據(jù)obj.reset = function(marketPosition, openPrice, N, leavePeriod, preBreakoutFailure) {if (typeof(marketPosition) !== 'undefined') {obj.marketPosition = marketPositionobj.openPrice = openPriceobj.preBreakoutFailure = preBreakoutFailureobj.N = Nobj.leavePeriod = leavePeriodvar pos = obj.getPosition(exchange, obj.tradeSymbol)if (pos) {obj.holdPrice = pos.Priceobj.holdAmount = pos.AmountLog(obj.symbol, "倉位", pos)} else {throw "恢復(fù)" + obj.symbol + "的持倉狀態(tài)出錯, 沒有找到倉位信息"}Log("恢復(fù)", obj.symbol, "加倉次數(shù)", obj.marketPosition, "持倉均價:", obj.holdPrice, "持倉數(shù)量:", obj.holdAmount, "最后一次加倉價", obj.openPrice, "N值", obj.N, "離市周期:", leavePeriod, "上次突破:", obj.preBreakoutFailure ? "失敗" : "成功")obj.status.open = 1obj.status.vm = [obj.marketPosition, obj.openPrice, obj.N, obj.leavePeriod, obj.preBreakoutFailure]} else {obj.marketPosition = 0obj.holdPrice = 0obj.openPrice = 0obj.holdAmount = 0obj.holdProfit = 0obj.preBreakoutFailure = true // test system Aobj.N = 0obj.leavePeriod = leavePeriodA}obj.holdProfit = 0obj.lastErr = ""obj.lastErrTime = ""}// 獲取控制對象狀態(tài)信息obj.Status = function() {obj.status.N = obj.Nobj.status.marketPosition = obj.marketPositionobj.status.holdPrice = obj.holdPriceobj.status.holdAmount = obj.holdAmountobj.status.lastPrice = obj.lastPriceif (obj.lastPrice > 0 && obj.holdAmount > 0 && obj.marketPosition !== 0) {obj.status.holdProfit = _N((obj.lastPrice - obj.holdPrice) * obj.holdAmount * obj.symbolDetail.VolumeMultiple, 4) * (obj.marketPosition > 0 ? 1 : -1)} else {obj.status.holdProfit = 0}obj.status.symbolDetail = obj.symbolDetailreturn obj.status}// 執(zhí)行海龜交易邏輯obj.Poll = function() {obj.status.isTrading = obj.isSymbolTrading(obj.symbol)if (!obj.status.isTrading) {return}var suffix = WXPush ? '@' : ''// switch symbolvar insDetail = exchange.SetContractType(obj.symbol)if (!insDetail) {return}// 獲取tick數(shù)據(jù)var ticker = exchange.GetTicker()if (!ticker) {obj.setLastError("獲取tick失敗")return}if (IsVirtual()) {ticker.Info = {}ticker.Info.LotSize = obj.symbolDetail.VolumeMultipleticker.Info.PriceSpread = 0.01}var records = exchange.GetRecords()if (!records) {obj.setLastError("獲取K線失敗")return}obj.status.recordsLen = records.lengthif (records.length < obj.atrLen) {obj.setLastError("K線長度小于 " + obj.atrLen)return}var opCode = 0 // 0: IDLE, 1: LONG, 3: CoverALLvar lastPrice = records[records.length - 1].Closeobj.lastPrice = lastPriceif (obj.marketPosition === 0) {obj.status.stopPrice = '--'obj.status.leavePrice = '--'obj.status.upLine = 0obj.status.downLine = 0for (var i = 0; i < 2; i++) {if (i == 0 && obj.useFilter && !obj.preBreakoutFailure) {continue}var enterPeriod = i == 0 ? obj.enterPeriodA : obj.enterPeriodBif (records.length < (enterPeriod + 1)) {continue}var highest = TA.Highest(records, enterPeriod, 'High')var lowest = TA.Lowest(records, enterPeriod, 'Low')obj.status.upLine = obj.status.upLine == 0 ? highest : Math.min(obj.status.upLine, highest)obj.status.downLine = obj.status.downLine == 0 ? lowest : Math.max(obj.status.downLine, lowest)if (lastPrice > highest) {opCode = 1}if (opCode != 0) {obj.leavePeriod = (enterPeriod == obj.enterPeriodA) ? obj.leavePeriodA : obj.leavePeriodBbreak}}} else {var spread = obj.marketPosition > 0 ? (obj.openPrice - lastPrice) : (lastPrice - obj.openPrice)obj.status.stopPrice = _N(obj.openPrice + (obj.N * StopLossRatio * (obj.marketPosition > 0 ? -1 : 1)))if (spread > (obj.N * StopLossRatio)) {opCode = 3obj.preBreakoutFailure = trueLog(obj.symbolDetail.InstrumentName, "止損平倉", suffix)obj.status.st++} else if (-spread > (IncSpace * obj.N) && Math.abs(obj.marketPosition) < obj.maxLots) {opCode = obj.marketPosition > 0 ? 1 : 2}if (opCode == 0 && records.length > obj.leavePeriod) {obj.status.leavePrice = obj.marketPosition > 0 ? TA.Lowest(records, obj.leavePeriod, 'Low') : TA.Highest(records, obj.leavePeriod, 'High')if ((obj.marketPosition > 0 && lastPrice < obj.status.leavePrice) ||(obj.marketPosition < 0 && lastPrice > obj.status.leavePrice)) {obj.preBreakoutFailure = falseLog(obj.symbolDetail.InstrumentName, "正常平倉", suffix)opCode = 3obj.status.cover++}}}if (opCode == 0) {return}if (opCode == 3) {var pos = obj.getPosition(exchange, obj.tradeSymbol)obj.sell(exchange, obj.tradeSymbol, pos.Amount, ticker.Info)obj.reset()_G(obj.symbol, null)var account = _C(exchange.GetAccount)return}// Openif (Math.abs(obj.marketPosition) >= obj.maxLots) {obj.setLastError("禁止開倉, 超過最大持倉 " + obj.maxLots)return}var atrs = TA.ATR(records, atrLen)var N = _N(atrs[atrs.length - 1], 4)var account = _C(exchange.GetAccount)var unit = parseInt((obj.initBalance-obj.keepBalance) * (obj.riskRatio / 100) / N / obj.symbolDetail.VolumeMultiple)var canOpen = parseInt((account.Balance-obj.keepBalance) / (lastPrice * 1.2) / obj.symbolDetail.VolumeMultiple)unit = Math.min(unit, canOpen)unit = unit * obj.symbolDetail.VolumeMultipleif (unit < obj.symbolDetail.VolumeMultiple) {obj.setLastError("可開 " + unit + " 手 無法開倉, " + (canOpen >= obj.symbolDetail.VolumeMultiple ? "風(fēng)控觸發(fā)" : "資金限制") + "。 可用: " + account.Balance)return}// 交易函數(shù)if (opCode == 2) {throw "股票不支持做空"}var ret = obj.buy(exchange, obj.tradeSymbol, unit, ticker.Info)if (ret) {Log(obj.symbolDetail.InstrumentName, obj.marketPosition == 0 ? "開倉" : "加倉", "離市周期", obj.leavePeriod, suffix)obj.N = Nobj.openPrice = ticker.Lastobj.holdPrice = ret.Priceif (obj.marketPosition == 0) {obj.status.open++}obj.holdAmount = ret.Amountobj.marketPosition += opCode == 1 ? 1 : -1obj.status.vm = [obj.marketPosition, obj.openPrice, N, obj.leavePeriod, obj.preBreakoutFailure]_G(obj.symbol, obj.status.vm)} else {obj.setLastError("下單失敗")return}}var vm = nullif (RMode === 0) {vm = _G(obj.symbol)} else {vm = JSON.parse(VMStatus)[obj.symbol]}if (vm) {Log("準(zhǔn)備恢復(fù)進度, 當(dāng)前合約狀態(tài)為", vm)obj.reset(vm[0], vm[1], vm[2], vm[3], vm[4])} else {if (needRestore) {Log("沒有找到" + obj.symbol + "的進度恢復(fù)信息")}obj.reset()}return obj} }function onexit() {Log("已退出策略...") }function main() {if((!IsVirtual() && exchange.GetCurrency() != "STOCK" && exchange.GetName() != "Futures_Futu") || (IsVirtual() && exchange.GetCurrency() != "STOCK_CNY" && exchange.GetName() != "Futures_XTP")) {Log("currency:", exchange.GetCurrency(), "name:", exchange.GetName())throw "不支持"}SetErrorFilter("login|ready|流控|連接失敗|初始|Timeout|market not ready")while (!exchange.IO("status")) {Sleep(3000)LogStatus("正在等待與交易服務(wù)器連接, " + _D())}var positions = _C(exchange.GetPosition)if (positions.length > 0) {Log("檢測到當(dāng)前持有倉位, 系統(tǒng)將開始嘗試恢復(fù)進度...")Log("持倉信息", positions)}Log("風(fēng)險系數(shù):", RiskRatio, "N值周期:", ATRLength, "系統(tǒng)1: 入市周期", EnterPeriodA, "離市周期", LeavePeriodA, "系統(tǒng)二: 入市周期", EnterPeriodB, "離市周期", LeavePeriodB, "加倉系數(shù):", IncSpace, "止損系數(shù):", StopLossRatio, "單品種最多開倉:", MaxLots, "次")var initAccount = _C(exchange.GetAccount)var realInitBalance = initAccount.Balanceif (CustomBalance) {realInitBalance = InitBalanceLog("自定義啟動資產(chǎn)為", realInitBalance)}var keepBalance = _N(realInitBalance * (KeepRatio/100), 3)Log("當(dāng)前資產(chǎn)信息", initAccount, "保留資金:", keepBalance)var tts = []var filter = []var arr = Instruments.split(',')for (var i = 0; i < arr.length; i++) {var symbol = arr[i].replace(/^\s+/g, "").replace(/\s+$/g, "");if (typeof(filter[symbol]) !== 'undefined') {Log(symbol, "已經(jīng)存在, 系統(tǒng)已自動過濾")continue}filter[symbol] = truevar hasPosition = falsefor (var j = 0; j < positions.length; j++) {if (positions[j].ContractType == symbol) {hasPosition = truebreak}}var obj = TTManager.New(hasPosition, symbol, realInitBalance, keepBalance, RiskRatio, ATRLength, EnterPeriodA, LeavePeriodA, EnterPeriodB, LeavePeriodB, UseEnterFilter, IncSpace, StopLossRatio, MaxLots)tts.push(obj)}var tblAssets = nullvar nowAccount = nullvar lastStatus = ''while (true) {if (GetCommand() === "暫停/繼續(xù)") {Log("暫停交易中...")while (GetCommand() !== "暫停/繼續(xù)") {Sleep(1000)}Log("繼續(xù)交易中...")}while (!exchange.IO("status")) {Sleep(3000)LogStatus("正在等待與交易服務(wù)器連接, " + _D() + "\n" + lastStatus)}var tblStatus = {type: "table",title: "持倉信息",cols: ["合約名稱", "持倉方向", "持倉均價", "持倉數(shù)量", "持倉盈虧", "加倉次數(shù)", "開倉次數(shù)", "止損次數(shù)", "成功次數(shù)", "當(dāng)前價格", "N"],rows: []}var tblMarket = {type: "table",title: "運行狀態(tài)",cols: ["合約名稱", "合約乘數(shù)", "保證金率", "交易時間", "移倉次數(shù)", "柱線長度", "上線", "下線", "止損價", "離市價", "異常描述", "發(fā)生時間"],rows: []}var totalHold = 0var vmStatus = {}var ts = new Date().getTime()var holdSymbol = 0var tradingCount = 0for (var i = 0; i < tts.length; i++) {tts[i].Poll()var d = tts[i].Status()if (d.holdAmount > 0) {vmStatus[d.symbol] = d.vmholdSymbol++}if (d.isTrading) {tradingCount++}tblStatus.rows.push([d.symbolDetail.InstrumentID + "/" + d.symbolDetail.InstrumentName, d.holdAmount == 0 ? '--' : (d.marketPosition > 0 ? '多' : '空'), d.holdPrice, d.holdAmount, d.holdProfit, Math.abs(d.marketPosition), d.open, d.st, d.cover, d.lastPrice, d.N])tblMarket.rows.push([d.symbolDetail.InstrumentID + "/" + d.symbolDetail.InstrumentName, d.symbolDetail.VolumeMultiple, _N(d.symbolDetail.LongMarginRatio, 4) + '/' + _N(d.symbolDetail.ShortMarginRatio, 4), (d.isTrading ? '是#0000ff' : '否#ff0000'), d.switchCount, d.recordsLen, d.upLine, d.downLine, d.stopPrice, d.leavePrice, d.lastErr, d.lastErrTime])totalHold += Math.abs(d.holdAmount)}var now = new Date()var elapsed = now.getTime() - tslastStatus = '`' + JSON.stringify([tblStatus, tblMarket]) + '`\n輪詢耗時: ' + elapsed + ' 毫秒, 當(dāng)前時間: ' + _D() + ', 星期' + ['日', '一', '二', '三', '四', '五', '六'][now.getDay()] + ", 持有品種個數(shù): " + holdSymbol + ", 手動恢復(fù)字符串: " + JSON.stringify(vmStatus)LogStatus(lastStatus)Sleep(LoopInterval * 1000)} }

回測測試、研究
我們選擇幾只股票回測:600519.SH,600690.SH,600006.SH,601328.SH,600887.SH,600121.SH,601633.SH。

其它參數(shù)設(shè)置:

回測時狀態(tài)欄信息輸出:

可以觀察到,海龜交易法這種趨勢跟蹤策略需要在有較大的行情時才會有較好的盈利。在行情反復(fù)震蕩時可能會有一定回撤。
漲幅較大的貴州茅臺貢獻(xiàn)了整體收益的絕大部分,看來選股也是十分重要的因素。并且根據(jù)狀態(tài)欄中顯示的統(tǒng)計數(shù)據(jù)來看,海龜交易法的止損次數(shù)要遠(yuǎn)高于策略成功盈利次數(shù)。這也是策略的思路核心,用較小的頭寸試錯。一旦抓住趨勢突破加倉,抓住肥尾。創(chuàng)造震蕩期損失數(shù)倍的盈利。
完整策略:https://www.fmz.cn/strategy/346551
該策略僅用于回測研究,實盤請自行優(yōu)化、修改。

總結(jié)

以上是生活随笔為你收集整理的说说海龟交易法则的基本原理,如何实现海龟交易策略?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。