Aberrationsstrategie

Schriftsteller:Kleine Träume, Erstellt: 2016-12-10 12:53:45, Aktualisiert: 2016-12-10 12:57:30

Aberration ist die Strategie, um mit Trends Geld zu verdienen.


  • Einführung

Viele Freunde, die sich auf Intuition-Futures verlassen, sind vielleicht ein wenig unbekannt mit der Aberration-Strategie, dem legendären Handelssystem, das 1986 von Keith Fitschen erfunden wurde. Er veröffentlichte es 1993 in der US-amerikanischen Zeitschrift Future Truth. Seit seiner Veröffentlichung hat es die erste Position in den Performance-Listen der bereits veröffentlichten Handelssysteme in 1997, 2001 und 2005 erreicht. Es handelt sich um ein mittel-langfristiges Handelssystem mit einer Trendverfolgungsstrategie, das flexibel zwischen acht Sorten von Getreide, Fleisch, Metallen, Energie, Devisen, Aktien-Futures und anderen Trends abläuft, um Profite zu erzielen. Da es gleichzeitig in mehreren unabhängigen oder wenig relevanten Märkten gehandelt wird, kann ein hoher Trendgewinn in einem oder mehreren Märkten die Verluste in anderen instabilen Märkten ausgleichen. Die Strategie des Eröffnungs-Platzierungs-Strategies ist folgender: Erst die 35-tägige gleitende Durchschnittslinie und die Standarddifferenz des 35-tägigen Schlusskurses nutzen, um die drei oberen, mittleren und unteren Tracks zu ermitteln, bei denen der Schlusskurs eines Bars mehr auf der Spur ist, der untere auf der Spur ist, der untere auf der Spur ist, der untere auf der Spur ist, der untere auf der Mittelstrecke ist, der oberste auf der Mittelstrecke ist. Die Idee der Strategie ist ganz einfach: Man nutzt die gleitenden Mittelwerte und die Standarddifferenzen, um zu jeder Zeit zu entscheiden, ob man den Tunnel durchbrochen hat, um den Trend zu erfassen. Wenn der Trend schrittweise abschwächt, nimmt er zuerst ab, weil die Mittelbahn abklingt. Wenn die K-Linie umgekehrt durch die Mittelbahn geht, kann man den Trend als beendet betrachten und den Ausgang stoppen. Die Strategie wurde früher veröffentlicht und ist in der heutigen Handelsbranche vielleicht nicht mehr sehr anwendbar, aber die Idee, Trends zu erfassen, ist langlebig.

  • Einführung 2.

    Das Abberation-Trading-System wurde 1986 von Keith Fitschen erfunden und 1993 in der Zeitschrift Future Trust veröffentlicht. Interessanterweise war Keith kein geborener Trader. Das Abberation-Tradingsystem ist charakterisiert durch passives Trendfolgen, mit langfristigen Signalen, das 3-4 Mal pro Jahr in einer Sorte gehandelt wird, die mehr als 60% der gesamten Handelszeit hält, und die Anzahl der Sorten je nach Kapitalgröße aufgeteilt werden kann. Es erzielt große Gewinne, indem es durch langfristige Transaktionen Trends erfasst, während es in mehreren unabhängigen Märkten gehandelt wird, und wenn eine Sorte zurücktritt, kann eine andere Sorte gewinnen. Insbesondere wird das Abberation-System mit 3 Tracks gehandelt. Zuerst wird der arithmetische Durchschnitt des letzten N-Tage-Abschlusspreises der Sorte (MA close) als Mittelstrecke (MID) berechnet, mit dem Standarddifferenzstd (close) als Maß für die Volatilität des Abschlusspreises und berechnet auf der Strecke (MID + m).std ((close) und unterbahn MID-mstd ((close) ); mehr, wenn der Preis die Bahn durchbricht, ausgeglichen, wenn der Preis in die Mitte zurückkehrt; umgekehrt, mehr, wenn der Preis die Bahn durchbricht und ausgeglichen, wenn der Preis in die Mitte zurückkehrt.

  • Die Strategie

    Aberration ist auch ein Tunnelbrechersystem, dessen Auf- und Abfahrt jedoch durch die Schwankungsrate bestimmt wird.

    1. Feststellung des Auf- und Abfahrts: Aberration besteht aus drei Kanallinien, wobei die Mittelbahn eine bewegliche Durchschnittslinie ("AveMa") für einen bestimmten Zeitraum ist, und die Ober-Unterbahn eine bestimmte Preisstandardabweichung ("StdValue") auf der Basis der Mittelbahn ist, die wir als die bekannten Braun-Linien kennen, und die Systemkonstruktion ist sehr prägnant.

    Die Berechnung erfolgt wie folgt: (1) Berechnung der Mittelbahn: AveMa=Average ((Close[1],Length); (2) Berechnung des Standardfehlers: StdValue = StandardDev ((Close[1],Length); (3) Berechnung auf der Strecke: UpperBand=Avema+StdDevUpStdValue; (StdDevUp ist der Bahnparameter) (4) Berechnung der Unterbahn: LowerBand=Avema-StdDevDnStdValue; (StdDevDn ist der Unterbahnparameter)

    2. Kauf- und Verkaufsbedingungen: Der Preis für den Schlussprozess ist im Vergleich zu dem für den Vorgang der letzten Woche deutlich niedriger als für den Vorgang der letzten Woche. Der Markt ist in der Lage, sich zu bewegen, wenn die Marktanteile nicht überschritten werden, und die Marktanteile werden nicht überschritten.

  • Strategie-Quellcode

    • Strategie-Rahmen ist logisch klar und wiederverwendbar
    • Realzeit-Debugging, wenn Interaktionsfunktionen auf der Festplatte ausgeführt werden
    • Es funktioniert stabil und die Details sind perfekt.
    • Unterstützt mehrere gleichzeitige Operationen und kann die Auslagerung individuell steuern
    • Automatisierte Wiederherstellung des Fortschritts nach Position beim Neustart
    • Mit einem Modul zur Windsteuerung können Risiken in Echtzeit angezeigt und Schäden gestoppt werden.
    • WeChat-Nachricht für den nächsten Tag
    • Wer keinen Server mieten möchte, kann mit seinem eigenen Computer oder mit einer Raspberry-Pie Windows, Linux oder Mac-Systeme laufen lassen, auch wenn der Router ausgebrannt ist.
function Aberration(q, e, symbol, period, upRatio, downRatio, opAmount) {
    var self = {}
    self.q = q
    self.e = e
    self.symbol = symbol
    self.upTrack = 0
    self.middleTrack = 0
    self.downTrack = 0
    self.nPeriod = period
    self.upRatio = upRatio
    self.downRatio = downRatio
    self.opAmount = opAmount
    self.marketPosition = 0

    self.lastErrMsg = ''
    self.lastErrTime = ''
    self.lastBar = {
        Time: 0,
        Open: 0,
        High: 0,
        Low: 0,
        Close: 0,
        Volume: 0
    }
    self.symbolDetail = null
    self.lastBarTime = 0
    self.tradeCount = 0
    self.isBusy = false

    self.setLastError = function(errMsg) {
        self.lastErrMsg = errMsg
        self.lastErrTime = errMsg.length > 0 ? _D() : ''
    }

    self.getStatus = function() {
        return [self.symbol, self.opAmount, self.upTrack, self.downTrack, self.middleTrack, _N(self.lastBar.Close), (self.marketPosition == 0 ? "--" : (self.marketPosition > 0 ? "多#ff0000" : "空#0000ff")), self.tradeCount, self.lastErrMsg, self.lastErrTime]
    }
    self.getMarket = function() {
        return [self.symbol, _D(self.lastBarTime), _N(self.lastBar.Open), _N(self.lastBar.High), _N(self.lastBar.Low), _N(self.lastBar.Close), self.lastBar.Volume]
    }

    self.restore = function(positions) {
        for (var i = 0; i < positions.length; i++) {
            if (positions[i].ContractType == self.symbol) {
                self.marketPosition += positions[i].Amount * ((positions[i].Type == PD_LONG || positions[i].Type == PD_LONG_YD) ? 1 : -1)
            }
        }
        if (self.marketPosition !== 0) {
            self.tradeCount++
                Log("恢复", self.symbol, "当前持仓为", self.marketPosition)
        }
    }

    self.poll = function() {
        if (self.isBusy) {
            return false
        }

        if (!$.IsTrading(self.symbol)) {
            self.setLastError("不在交易时间内")
            return false
        }

        if (!self.e.IO("status")) {
            self.setLastError("未连接交易所")
            return false
        }

        var detail = self.e.SetContractType(self.symbol)
        if (!detail) {
            self.setLastError("切换合约失败")
            return false
        }
        if (!self.symbolDetail) {
            self.symbolDetail = detail
            Log("合约", detail.InstrumentName.replace(/\s+/g, ""), ", 策略一次开仓:", self.opAmount, "手, 一手", detail.VolumeMultiple, "份, 最大下单量", detail.MaxLimitOrderVolume, "保证金率:", detail.LongMarginRatio.toFixed(4), detail.ShortMarginRatio.toFixed(4), "交割日期", detail.StartDelivDate);
        }
        var records = self.e.GetRecords()
        if (!records || records.length == 0) {
            self.setLastError("获取柱线失败")
            return false
        }

        var bar = records[records.length - 1]
        self.lastBar = bar

        if (records.length <= self.nPeriod) {
            self.setLastError("柱线长度不够")
            return false
        }

        if (self.lastBarTime < bar.Time) {
            var sum = 0
            var pos = records.length - self.nPeriod - 1
            for (var i = pos; i < records.length - 1; i++) {
                sum += records[i].Close
            }
            var avg = sum / self.nPeriod
            var std = 0
            for (i = pos; i < records.length - 1; i++) {
                std += Math.pow(records[i].Close - avg, 2)
            }
            std = Math.sqrt(std / self.nPeriod)

            self.upTrack = _N(avg + (self.upRatio * std))
            self.downTrack = _N(avg - (self.downRatio * std))
            self.middleTrack = _N(avg)
            self.lastBarTime = bar.Time
        }
        var msg
        var act = ""
        if (self.marketPosition == 0) {
            if (bar.Close > self.upTrack) {
                msg = '做多 触发价: ' + bar.Close + ' 上轨:' + self.upTrack;
                act = "buy"
            } else if (bar.Close < self.downTrack) {
                msg = '做空 触发价: ' + bar.Close + ' 下轨:' + self.downTrack;
                act = "sell"
            }
        } else {
            if (self.marketPosition < 0 && bar.Close > self.middleTrack) {
                msg = '平空 触发价: ' + bar.Close + ' 平仓线:' + self.middleTrack;
                act = "closesell"
            } else if (self.marketPosition > 0 && bar.Close < self.middleTrack) {
                msg = '平多 触发价: ' + bar.Close + ' 平仓线:' + self.middleTrack;
                act = "closebuy"
            }
        }

        if (act == "") {
            return true
        }

        Log(self.symbol + ', ' + msg + (NotifyWX ? '@' : ''))

        self.isBusy = true
        self.tradeCount += 1
        if (self.lastErrMsg != '') {
            self.setLastError('')
        }
        self.q.pushTask(self.e, self.symbol, act, self.opAmount, function(task, ret) {
            self.isBusy = false
            if (!ret) {
                return
            }
            if (task.action == "buy") {
                self.marketPosition = 1
            } else if (task.action == "sell") {
                self.marketPosition = -1
            } else {
                self.marketPosition = 0
            }
        })
    }
    return self
}

function main() {
    if (exchange.GetName() !== 'Futures_CTP') {
        throw "只支持传统商品期货(CTP)"
    }
    
    SetErrorFilter("login|ready|初始化")

    LogStatus("Ready...")
    if (Reset) {
        LogProfitReset()
        LogReset()
    }
    
    // Ref: https://www.fmz.com/bbs-topic/362
    if (typeof(exchange.IO("mode", 0)) == 'number') {
        Log("切换行情模式成功")
    }

    LogStatus("等待与期货商服务器连接..")
    while (!exchange.IO("status")) {
        Sleep(500)
    }
    LogStatus("获取资产信息")
    var tblRuntime = {
        type: 'table',
        title: '交易信息',
        cols: ['品种', '每次开仓量', '上轨', '下轨', '中轨', '最后成交价', '仓位', '交易次数', '最后错误', '错误时间'],
        rows: []
    };
    var tblMarket = {
        type: 'table',
        title: '行情信息',
        cols: ['品种', '当前周期', '开盘', '最高', '最低', '最后成交价', '成交量'],
        rows: []
    };
    var tblPosition = {
        type: 'table',
        title: '持仓信息',
        cols: ['品种', '杠杆', '方向', '均价', '数量', '持仓盈亏'],
        rows: []
    };
    var positions = _C(exchange.GetPosition)
    if (positions.length > 0 && !AutoRestore) {
        throw "程序启动时不能有持仓, 但您可以勾选自动恢复来进行自动识别 !"
    }
    var initAccount = _C(exchange.GetAccount)
    var detail = JSON.parse(exchange.GetRawJSON())
    if (positions.length > 0) {
        initAccount.Balance += detail['CurrMargin']
    }
    var initNetAsset = detail['CurrMargin'] + detail['Available']
    var initAccountTbl = $.AccountToTable(exchange.GetRawJSON(), "初始资金")

    if (initAccountTbl.rows.length == 0) {
        initAccountTbl.rows = [
            ['Balance', '可用保证金', initAccount.Balance],
            ['FrozenBalance', '冻结资金', initAccount.FrozenBalance]
        ]
    }

    var nowAcccount = initAccount
    var nowAcccountTbl = initAccountTbl

    var symbols = Symbols.replace(/\s+/g, "").split(',')
    var pollers = []
    var prePosUpdate = 0
    var suffix = ""
    var needUpdate = false
    var holdProfit = 0

    function updateAccount(acc) {
        nowAcccount = acc
        nowAcccountTbl = $.AccountToTable(exchange.GetRawJSON(), "当前资金")
        if (nowAcccountTbl.rows.length == 0) {
            nowAcccountTbl.rows = [
                ['Balance', '可用保证金', nowAcccount.Balance],
                ['FrozenBalance', '冻结资金', nowAcccount.FrozenBalance]
            ]
        }
    }

    var q = $.NewTaskQueue(function(task, ret) {
        needUpdate = true
        Log(task.desc, ret ? "成功" : "失败")
        var account = task.e.GetAccount()
        if (account) {
            updateAccount(account)
        }
    })

    _.each(symbols, function(symbol) {
        var pair = symbol.split(':')
        pollers.push(Aberration(q, exchange, pair[0], NPeriod, Ks, Kx, (pair.length == 1 ? AmountOP : parseInt(pair[1]))))
    })

    if (positions.length > 0 && AutoRestore) {
        _.each(pollers, function(poll) {
            poll.restore(positions)
        })
    }
    var isFirst = true
    while (true) {
        var cmd = GetCommand()
        if (cmd) {
            var js = cmd.split(':', 2)[1]
            Log("执行调试代码:", js)
            try {
                eval(js)
            } catch (e) {
                Log("Exception", e)
            }
        }
        tblRuntime.rows = []
        tblMarket.rows = []
        var marketAlive = false
        _.each(pollers, function(poll) {
            if (poll.poll()) {
                marketAlive = true
            }
            tblRuntime.rows.push(poll.getStatus())
            tblMarket.rows.push(poll.getMarket())
        })
        q.poll()
        Sleep(LoopInterval * 1000)
        if ((!exchange.IO("status")) || (!marketAlive)) {
            if (isFirst) {
                LogStatus("正在等待开盘...", _D())
            }
            continue
        }
        isFirst = false
        var now = new Date().getTime()
        if (marketAlive && (now - prePosUpdate > 30000 || needUpdate)) {
            var pos = exchange.GetPosition()
            if (pos) {
                holdProfit = 0
                prePosUpdate = now
                tblPosition.rows = []
                for (var i = 0; i < pos.length; i++) {
                    tblPosition.rows.push([pos[i].ContractType, pos[i].MarginLevel, ((pos[i].Type == PD_LONG || pos[i].Type == PD_LONG_YD) ? '多#ff0000' : '空#0000ff'), pos[i].Price, pos[i].Amount, _N(pos[i].Profit)])
                    holdProfit += pos[i].Profit
                }
                if (pos.length == 0 && needUpdate) {
                    LogProfit(_N(nowAcccount.Balance - initAccount.Balance, 4), nowAcccount)
                }
            }
            needUpdate = false
            if (RCMode) {
                var account = exchange.GetAccount()
                if (account) {
                    updateAccount(account)
                    var detail = JSON.parse(exchange.GetRawJSON())
                    var netAsset = detail['PositionProfit'] + detail['CurrMargin'] + detail['Available']
                    var risk = detail['CurrMargin'] / (detail['CurrMargin'] + detail['Available'] + detail['PositionProfit'])
                    suffix = ", 账户初始净值约: " + _N(initNetAsset, 2) + " , 风控最小净值要求" + MinNetAsset + " , 当前账户净值约: " + _N(netAsset, 2) + ", 盈亏约: " + _N(netAsset - initNetAsset, 3) + " 元, 风险: " + ((risk * 100).toFixed(3)) + "% #ff0000"
                    if (netAsset < MinNetAsset) {
                        Log("风控模块触发, 中止运行并平掉所有仓位, 当前净值约 ", netAsset, ", 要求低于最小净值:", MinNetAsset)
                        if (RCCoverAll) {
                            Log("开始平掉所有仓位")
                            $.NewPositionManager().CoverAll()
                        }
                        throw "中止运行"
                    }
                }
            }
        }
        LogStatus('`' + JSON.stringify([tblRuntime, tblPosition, tblMarket, initAccountTbl, nowAcccountTbl]) + '`\n价格最后更新: ' + _D() + ', 持仓最后更新: ' + _D(prePosUpdate) + '\n当前持仓总盈亏: ' + _N(holdProfit, 3) + suffix)
    }
}
  • Ergebnisse der Tests

    Das System ist so stark, dass es nur durch die Konstruktion eines Portfolios funktioniert.img

  • Zusammenfassung

    1. Die Strategie ist sehr vielfältig und zyklisch anpassungsfähig und eignet sich für die meisten Handelsvarianten. 2. Die Strategie des Rückzugs ist groß und erfordert eine strenge Finanzverwaltung und Risikokontrolle.


Mehr