Многие друзья, которые играют на интуитивных фьючерсах, могут быть немного незнакомы с стратегией Aberration, легендарной торговой системой, которая создавала более 100% годовой доходности, изобретенной Китом Фитченом в 1986 году. В 1993 году он опубликовал ее в американском журнале Future Truth, и с момента публикации стратегии ее производительность постоянно занимала первое место в рейтинге результатов, выпущенных в 1997, 2001 и 2005 годах. Это средне-длиннолинейная торговая система, относящаяся к стратегии тренд-следателя, которая гибко работает между 8 сортами зерна, мяса, металлов, энергии, валюты, фондовых индексов и т. д. и получает прибыль путем длиннолинейного слежения за тенденциями. Поскольку она одновременно торгует на нескольких несвязанных или мало связанных рынках, высокая прибыль от тренда на одном или нескольких рынках компенсирует убытки на других нестабильных рынках. Стратегия открытия позиции в этой стратегии выглядит следующим образом: сначала используется 35-дневная движущаяся средняя и 35-дневная стандартная разница в цене закрытия, чтобы получить три верхних и нижних траектории, когда цена закрытия в одном Баре проходит через трассу, когда она проходит через трассу, когда она проходит через трассу. Идея этой стратегии очень проста: использовать движущийся средний и стандартный дифференцированный канал, а затем в любое время судить о том, прорвался ли канал, чтобы поймать тренд. А когда тренд постепенно ослабевает, он начинает ослабевать, так что, когда линия K переходит через центральную трассу обратно, можно считать, что тренд закончился и остановить выход. Эта стратегия была выпущена раньше, и, возможно, уже не очень применима в современных условиях торговли, но идея захвата трендов остается неизменной.
Abberation Trading System была изобретена Китом Фитченом в 1986 году и опубликована в журнале Future Trust в 1993 году. Интересно, что Кит не был рожден трейдером, он служил в ВВС США более 20 лет, специализируясь на навигационных системах оружия, обладающих глубокой силой в обработке данных временных рядов. Абберационная торговая система характеризуется пассивным следованием тенденциям, использованием долгосрочных сигналов, торгуя 3-4 раза в год на одном сортке, сдерживая более 60% от общего времени торговли, и распределяя количество сорта в зависимости от разного размера капитала. Она получает огромную прибыль, поскольку длинные сделки улавливают тенденции, а в то же время торгуют на нескольких несвязанных рынках, когда один сорт отступает, другой может получить огромную прибыль. В частности, система Abberation использует три траектории для торговли. Сначала рассчитывается средний MA (close) за последние N дней закрытия, как средний траекторий (MID), а затем измеряется волатильность с стандартным отклонением std (close) за закрытие, как траекторийный MID+m.std ((close) и MID-mstd ((close) ); больше делать, когда цена прорывается вверх по траектории, а когда цена возвращается в середину траектории, равномерно; наоборот, делать пустое, когда цена прорывается вниз по траектории, равномерно, когда цена возвращается в середину траектории.
Аберрация также является системой прорыва каналов, однако ее путь вверх и вниз определяется частотой колебаний.
1, определение поезда: Аберрация состоит из трех канальных линий, в которых средний тракт представляет собой движущуюся среднюю линию (AveMa) определенного цикла, а верхний и нижний тракт - определенный стандартный разрыв цены (StdValue) на основе среднего тракта, т.е. известная нам линия Бринна, система которой очень просто и грамотно построена.
Процесс расчета выглядит следующим образом: (1) Вычислить средний траекторий: AveMa=Average ((Close[1],Length); (2) расчетный стандартный отклонение: StdValue = StandardDev ((Close[1],Length); (3) Вычислить на трассе: UpperBand=Avema+StdDevUpStdValue; (StdDevUp для параметров на пути) (4) Вычислить нижнюю полосу: LowerBand=Avema-StdDevDnStdValue; (StdDevDn для параметров на поезде)
Условия покупки: Повышение цены: цена закрытия переходит на более высокую ставку, а цена открытия - на более высокую ставку, а цена закрытия - на более высокую ставку, а цена закрытия - на более высокую ставку. Пустое место: цена закрытия упала ниже рельса, открыв пустую позицию, прорвав середину рельса.
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)
}
}
Поскольку система действует только при создании портфеля инвестиций.
1. Стратегия отличается превосходным разнообразием и гибкостью циклов и подходит для большинства видов торговли; В частности, в частности, в частности, в частности, в частности, в частности, в частности: