어버레이션 거래 전략www.fmz.com
어버레이션 거래 시스템은 키스 피츠헨에 의해 1986년에 발명되었다. 1993년 키스 피츠헨은 미래에셋 트루트 매거진에서 시스템을 상용화했다. 출시 이후 1997년, 2001년, 2005년에 지속적으로 최고의 순위에 올랐다. 이 시스템은 출판된 거래 시스템의 성능 순위에서 상위 10위 안에 있다. 이 거래 시스템은 곡물, 고기, 금속, 에너지, 외환, 금융 및 주식 지수 선물 등 8가지 다른 품종에 대한 동시 거래로 특징이다. 어버레이션 거래 시스템은 종종 1년에 3-4번 거래하며, 매매당 평균 60일 동안 60%의 포지션을 보유하고 있다. 트렌드를 포착하기 위해 장기 거래를 통해 막대한 수익을 얻는다.
유행은 유행이 없는 시장에서 작은 손실을 보상한다. 유행은 동시에 여러 개의 관련 없는 시장에서 거래하기 때문에, 한 종이 손실하면 다른 종이 수익을 올릴 수 있다. 한 해 동안, 항상 큰 수익을 올릴 수 있는 하나 이상의 품종이 있다. 이러한 큰 이익은 트렌드가 없는 시장에서 작은 손실을 보상한다. 유행 거래 시스템은 자금을 조합으로 관리하기 때문에 상대적으로 큰 금액을 받아들일 수 있다.
광선 선 차이도 볼링거 라인 거래 시스템을 기반으로 하지만 거래 목표가 볼링거 강도 시스템보다 길어 표준 편차 채널의 두 배를 사용할 수 있기 때문에, 그리고 손실 중지 사용되지 않습니다, 채널 지표 자체는 손실을 중지하는 데 사용됩니다.
다음 코드는 위의 아이디어의 틀에 불과합니다. 당신은 당신의 거래 선택에 대한 세부 사항을 조정해야합니다. 또한, 거래소 수수료와 다른 제한 정책에 주의하십시오.
코딩 프레임워크는 명확하고 재사용 가능합니다. 인터랙티브 함수를 실행할 때 실시간 디버깅 안정적인 작동, 완벽한 세부 디자인 동시에 여러 거래 품종을 지원, 개별적으로 거래 위치 금액을 제어 할 수 있습니다. 자동으로 재시작 시 위치에 따라 진행을 재개합니다. 리스크 제어 모듈을 통해 리스크 상황을 실시간으로 표시하고, 스톱 로스 상태를 표시합니다.
서버를 빌리고 싶지 않다면 자신의 컴퓨터나 라즈베리 파이나 윈도우, 리눅스 또는 맥 시스템을 사용하는 모든 컴퓨터를 사용할 수 있습니다.
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 ?
"Long#ff0000" : "short#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("restore", self.symbol, "Current position is", self.marketPosition)
}
}
self.poll = function() {
if (self.isBusy) {
return false
}
if (!$.IsTrading(self.symbol)) {
self.setLastError("Not in trading hours")
return false
}
if (!self.e.IO("status")) {
self.setLastError("Unconnected exchange")
return false
}
var detail = self.e.SetContractType(self.symbol)
if (!detail) {
self.setLastError("Switching contract failed")
return false
}
if (!self.symbolDetail) {
self.symbolDetail = detail
Log("contract", detail.InstrumentName.replace(/\s+/g, ""), ", Strategy first time to open a position:", self.opAmount, "hand, one hand", detail.VolumeMultiple, "unit, Maximum order quantity",
detail.MaxLimitOrderVolume, "Margin rate:", detail.LongMarginRatio.toFixed(4), detail.ShortMarginRatio.toFixed(4), "Delivery date", detail.StartDelivDate);
}
var records = self.e.GetRecords()
if (!records || records.length == 0) {
self.setLastError("Failed to get the bar line")
return false
}
var bar = records[records.length - 1]
self.lastBar = bar
if (records.length <= self.nPeriod) {
self.setLastError("The length of the bar line is not enough")
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 = 'Buying Long trigger price: ' + bar.Close + ' Upper rail:' + self.upTrack;
act = "buy"
} else if (bar.Close < self.downTrack) {
msg = 'Selling short trigger price: ' + bar.Close + ' lower rail:' + self.downTrack;
act = "sell"
}
} else {
if (self.marketPosition < 0 && bar.Close > self.middleTrack) {
msg = 'close the short position trigger price: ' + bar.Close + ' close position line:' + self.middleTrack;
act = "closesell"
} else if (self.marketPosition > 0 && bar.Close < self.middleTrack) {
msg = 'close the long position trigger price: ' + bar.Close + ' close position line:' + 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 "Only support traditional commodity futures(CTP)"
}
SetErrorFilter("login|ready|initialization")
LogStatus("Ready...")
if (Reset) {
LogProfitReset()
LogReset()
}
// Ref: https://www.fmz.com/bbs-topic/362
if (typeof(exchange.IO("mode", 0)) == 'number') {
Log("Switching the market mode successfully")
}
LogStatus("Waiting to connect with the futures dealer server..")
while (!exchange.IO("status")) {
Sleep(500)
}
LogStatus("Get asset information")
var tblRuntime = {
type: 'table',
title: 'Trading Information',
cols: ['Variety', 'Each open position volume', 'upper rail', 'lower rail', 'middle rail', 'last transaction price', 'position', 'transaction count', 'last error', 'error time'],
rows: []
};
var tblMarket = {
type: 'table',
title: 'Quote information',
cols: ['Variety', 'current cycle', 'opening', 'highest', 'lowest', 'last transaction price', 'volume'],
rows: []
};
var tblPosition = {
type: 'table',
title: 'Position information',
cols: ['Variety', 'leverage', 'direction', 'average price', 'quantity', 'holding profit and loss'],
rows: []
};
var positions = _C(exchange.GetPosition)
if (positions.length > 0 && !AutoRestore) {
throw "There can be no positions when the program starts, but you can check the automatic recovery for automatic identification!"
}
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(), "Initial funding")
if (initAccountTbl.rows.length == 0) {
initAccountTbl.rows = [
['Balance', 'Available margin', initAccount.Balance],
['FrozenBalance', 'Frozen funds', 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(), "Current funds")
if (nowAcccountTbl.rows.length == 0) {
nowAcccountTbl.rows = [
['Balance', 'Available margin', nowAcccount.Balance],
['FrozenBalance', 'Frozen funds', nowAcccount.FrozenBalance]
]
}
}
var q = $.NewTaskQueue(function(task, ret) {
needUpdate = true
Log(task.desc, ret ? "success" : "fail")
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("Execution debug code:", 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("Waiting for the market open...", _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) ? 'long#ff0000' : 'short#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 = ", Initial net worth of the account: " + _N(initNetAsset, 2) + " , risk control minimum net value requirement" + MinNetAsset + " , Current account equity: " + _N(netAsset, 2) +
", Profit and loss: " + _N(netAsset - initNetAsset, 3) + " yuan, risk: " + ((risk * 100).toFixed(3)) + "% #ff0000"
if (netAsset < MinNetAsset) {
Log("The risk control module triggers, stops running and closes all positions, the current net value is ", netAsset, ", Require less than the minimum net value:", MinNetAsset)
if (RCCoverAll) {
Log("Start to close all positions")
$.NewPositionManager().CoverAll()
}
throw "Stop running"
}
}
}
}
LogStatus('`' + JSON.stringify([tblRuntime, tblPosition, tblMarket, initAccountTbl, nowAcccountTbl]) + '`\nLast price update: ' + _D() +
', Last update of position: ' + _D(prePosUpdate) + '\nCurrent holding position total profit and loss: ' + _N(holdProfit, 3) + suffix)
}
}
작은 꿈잘했어