Strategi Aberration

Penulis:Mimpi kecil, Dicipta: 2016-12-10 12:53:45, Dikemas kini: 2016-12-10 12:57:30

Strategi Aberration untuk membuat wang dengan trend


  • Maklumat lanjut

Ramai rakan yang bermain dengan masa hadapan intuitif mungkin agak asing dengan strategi Aberration, sistem perdagangan legenda yang pernah menghasilkan pulangan tahunan lebih daripada 100% yang dicipta oleh Keith Fitschen pada tahun 1986. Pada tahun 1993, dia menerbitkan sistem ini di majalah Future Truth, Amerika Syarikat. Performa telah mencatatkan kedudukan teratas sejak tarikh penerbitan strategi, berada di kedudukan pertama dalam kedudukan prestasi sistem perdagangan yang telah dikeluarkan pada tahun 1997, 2001 dan 2005. Ia adalah sistem perdagangan yang mempunyai garis panjang dan sederhana, yang mempunyai strategi pengesanan trend. Ia beroperasi dengan fleksibel di antara lapan jenis seperti bijirin, daging, logam, tenaga, mata wang asing, masa hadapan indeks saham, dan lain-lain. Ia menghasilkan keuntungan dengan mengikuti trend secara garis panjang. Oleh kerana ia berdagang dalam beberapa pasaran yang tidak berkaitan atau kurang berkaitan pada masa yang sama, keuntungan tinggi dari trend hanya dalam satu atau beberapa pasaran dapat menebus kerugian dalam pasaran lain yang tidak stabil. Frekuensi dagangan umumnya adalah tiga hingga empat kali setahun, 60% masa ditempatkan, dengan purata 60 hari untuk setiap dagangan. Strategi pembukaan pegangan adalah sebagai berikut: pertama, menggunakan garis purata bergerak 35 hari dan perbezaan standard harga penutupan dalam 35 hari, untuk menghasilkan tiga lintasan atas dan bawah, apabila harga penutupan Bar berada di atas lintasan yang lebih tinggi, terbuka di bawah lintasan yang lebih rendah, berpusing di bawah lintasan yang lebih rendah, dan berpusing di atas lintasan yang lebih rendah. Idea strategi ini adalah mudah: menggunakan purata bergerak dan saluran yang ditetapkan dengan perbezaan standard, dan kemudian menilai pada bila-bila masa sama ada saluran itu telah ditembusi, dengan itu menangkap trend; dan apabila trend semakin lemah, kerana tengah lintasan akan cenderung untuk mereda terlebih dahulu, sehingga apabila garis K menembusi tengah lintasan, anda boleh menganggap trend itu telah berakhir dan berhenti berlari; dan jika terdapat salah faham trend, anda juga boleh menghentikan kerugian tepat pada masanya apabila garis K menembusi tengah lintasan. Strategi ini dikeluarkan lebih awal dan mungkin tidak sesuai dengan pasaran perdagangan sekarang, tetapi idea menangkap trend adalah kekal.

  • Keterangan

    Abberation Trading System dicipta oleh Keith Fitschen pada tahun 1986 dan diterbitkan dalam majalah Future Trust pada tahun 1993. Menariknya, Keith bukan seorang pedagang yang dilahirkan, dia berkhidmat di Tentera Udara Amerika Syarikat selama lebih dari 20 tahun, mengkhususkan diri dalam sistem navigasi senjata, yang mempunyai kekuatan yang mendalam dalam memproses data urutan masa. Sistem dagangan aberacion dicirikan oleh trend yang mengikuti secara pasif, menggunakan isyarat jangka panjang, berdagang 3-4 kali setahun pada satu varieti, memegang lebih daripada 60% masa dagangan keseluruhan, dan boleh mengalokasikan jumlah varieti yang berbeza mengikut ukuran modal yang berbeza. Ia memperoleh keuntungan besar dengan menangkap trend dengan perdagangan garis panjang, sementara berdagang di beberapa pasaran yang tidak berkaitan, apabila satu varieti menarik diri, yang lain mungkin mendapat keuntungan. Dalam tempoh setahun, selalu ada satu atau lebih varieti yang mendapat keuntungan besar. Secara khusus, sistem Abberation menggunakan 3 orbit untuk berdagang. Pertama, ia mengira purata aritmatika MA (close) harga penutupan N hari yang lalu untuk varieti ini sebagai mid-range (MID), dengan standard deviasi std (close) harga penutupan sebagai ukuran turun naik, dan mengira mid-range (MID + m).std ((close) dan bawah landasan MID-mstd ((close) ); melakukan lebih banyak apabila harga menembusi lintasan, berdamai apabila harga kembali ke lintasan tengah; sebaliknya, melakukan kosong apabila harga menembusi lintasan bawah, berdamai apabila harga kembali ke lintasan tengah.

  • Prinsip-prinsip strategi

    Aberration juga merupakan satu sistem penembusan saluran, tetapi laluan ke atas dan ke bawahnya ditentukan oleh kadar turun naik.

    1.Pengesahan laluan: Aberration terdiri daripada tiga saluran, di mana laluan tengah adalah purata bergerak pada satu kitaran tertentu (AveMa), laluan atas ke bawah adalah laluan tengah berdasarkan nilai standard harga tertentu (StdValue), iaitu garis Braun yang kita kenal, sistem yang dibina sangat ringkas dan indah.

    Proses pengiraan secara spesifik adalah sebagai berikut: (1) Mengira orbit: AveMa=Average ((Close[1],Length); (2) Kecacatan standard dikira: StdValue = StandardDev ((Close[1],Length); (3) Perkiraan di landasan: UpperBand=Avema+StdDevUpStdValue; (StdDevUp sebagai parameter atas laluan) (4) Pengiraan bawah jalur: LowerBand=Avema-StdDevDnStdValue; (StdDevDn untuk parameter bawah landasan)

    2. Syarat jual beli: Peningkatan harga: harga penutupan merentasi lintasan untuk membuka lebih banyak, jatuh di tengah-tengah lintasan; BOS: Harga penutupan jatuh di bawah landasan untuk membuka posisi kosong, menembusi tengah landasan keluar.

  • Kod sumber strategi

    • Rangka kerja strategi yang logiknya jelas, boleh digunakan semula
    • Debugging secara langsung semasa berjalan melalui cakera interaktif
    • Berjalan dengan stabil, dengan perincian yang sempurna
    • Sokongan untuk operasi serentak pelbagai jenis, boleh mengawal jumlah pembukaan secara berasingan
    • Memulihkan kemajuan secara automatik berdasarkan kedudukan semasa memulakan semula
    • Modul kawalan angin, menunjukkan risiko secara langsung, menghentikan kerosakan
    • Mesej di bawah:
    • Mereka yang tidak mahu menyewa pelayan boleh menggunakan komputer mereka sendiri atau menggunakan Windows, Linux, Mac, atau router yang selesai.
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)
    }
}
  • Hasil ujian

    Oleh kerana sistem ini hanya dapat memainkan kekuatan sistem dengan membina portfolio.img

  • Ringkasan

    1. Strategi ini mempunyai kepelbagaian dan kepelbagaian kitaran yang sangat baik, sesuai untuk kebanyakan jenis perdagangan; 2. Strategi ini adalah besar dan memerlukan pengurusan dana dan kawalan risiko yang ketat.


Lebih lanjut