TV上のスーパートレンド指標には複数のバージョンがあり,比較的に理解しやすいアルゴリズム移植を探し,発明者の量化取引プラットフォームリトークシステムTVグラフにロードされたスーパートレンド指標と比較して,わずかな違いを発見しました.
// VIA: https://github.com/freqtrade/freqtrade-strategies/issues/30
function SuperTrend(r, period, multiplier) {
// atr
var atr = talib.ATR(r, period)
// baseUp , baseDown
var baseUp = []
var baseDown = []
for (var i = 0; i < r.length; i++) {
if (isNaN(atr[i])) {
baseUp.push(NaN)
baseDown.push(NaN)
continue
}
baseUp.push((r[i].High + r[i].Low) / 2 + multiplier * atr[i])
baseDown.push((r[i].High + r[i].Low) / 2 - multiplier * atr[i])
}
// fiUp , fiDown
var fiUp = []
var fiDown = []
var prevFiUp = 0
var prevFiDown = 0
for (var i = 0; i < r.length; i++) {
if (isNaN(baseUp[i])) {
fiUp.push(NaN)
} else {
fiUp.push(baseUp[i] < prevFiUp || r[i - 1].Close > prevFiUp ? baseUp[i] : prevFiUp)
prevFiUp = fiUp[i]
}
if (isNaN(baseDown[i])) {
fiDown.push(NaN)
} else {
fiDown.push(baseDown[i] > prevFiDown || r[i - 1].Close < prevFiDown ? baseDown[i] : prevFiDown)
prevFiDown = fiDown[i]
}
}
var st = []
var prevSt = NaN
for (var i = 0; i < r.length; i++) {
if (i < period) {
st.push(NaN)
continue
}
var nowSt = 0
if (((isNaN(prevSt) && isNaN(fiUp[i - 1])) || prevSt == fiUp[i - 1]) && r[i].Close <= fiUp[i]) {
nowSt = fiUp[i]
} else if (((isNaN(prevSt) && isNaN(fiUp[i - 1])) || prevSt == fiUp[i - 1]) && r[i].Close > fiUp[i]) {
nowSt = fiDown[i]
} else if (((isNaN(prevSt) && isNaN(fiDown[i - 1])) || prevSt == fiDown[i - 1]) && r[i].Close >= fiDown[i]) {
nowSt = fiDown[i]
} else if (((isNaN(prevSt) && isNaN(fiDown[i - 1])) || prevSt == fiDown[i - 1]) && r[i].Close < fiDown[i]) {
nowSt = fiUp[i]
}
st.push(nowSt)
prevSt = st[i]
}
var up = []
var down = []
for (var i = 0; i < r.length; i++) {
if (isNaN(st[i])) {
up.push(st[i])
down.push(st[i])
}
if (r[i].Close < st[i]) {
down.push(st[i])
up.push(NaN)
} else {
down.push(NaN)
up.push(st[i])
}
}
return [up, down]
}
// 测试指标用的main函数,并非交易策略
function main() {
while (1) {
var r = _C(exchange.GetRecords)
var st = SuperTrend(r, 10, 3)
$.PlotRecords(r, "K")
$.PlotLine("L", st[0][st[0].length - 2], r[r.length - 2].Time)
$.PlotLine("S", st[1][st[1].length - 2], r[r.length - 2].Time)
Sleep(2000)
}
}
テストコードの復習対比:
取引の論理的な部分は,比較的シンプルで,空頭トレンドが多頭トレンドに変わるときに,多頭トレンドを開くことです. 多頭トレンドが空頭トレンドに変わると空位をオープンします.
戦略パラメータ:
スーパートレンドの取引戦略
/*backtest
start: 2019-08-01 00:00:00
end: 2020-03-11 00:00:00
period: 15m
basePeriod: 5m
exchanges: [{"eid":"Futures_OKCoin","currency":"BTC_USD"}]
*/
// 全局变量
var OpenAmount = 0 // 开仓后持仓的数量
var KeepAmount = 0 // 保留仓位
var IDLE = 0
var LONG = 1
var SHORT = 2
var COVERLONG = 3
var COVERSHORT = 4
var COVERLONG_PART = 5
var COVERSHORT_PART = 6
var OPENLONG = 7
var OPENSHORT = 8
var State = IDLE
// 交易逻辑部分
function GetPosition(posType) {
var positions = _C(exchange.GetPosition)
/*
if(positions.length > 1){
throw "positions error:" + JSON.stringify(positions)
}
*/
var count = 0
for(var j = 0; j < positions.length; j++){
if(positions[j].ContractType == Symbol){
count++
}
}
if(count > 1){
throw "positions error:" + JSON.stringify(positions)
}
for (var i = 0; i < positions.length; i++) {
if (positions[i].ContractType == Symbol && positions[i].Type === posType) {
return [positions[i].Price, positions[i].Amount];
}
}
Sleep(TradeInterval);
return [0, 0]
}
function CancelPendingOrders() {
while (true) {
var orders = _C(exchange.GetOrders)
for (var i = 0; i < orders.length; i++) {
exchange.CancelOrder(orders[i].Id);
Sleep(TradeInterval);
}
if (orders.length === 0) {
break;
}
}
}
function Trade(Type, Price, Amount, CurrPos, OnePriceTick){ // 处理交易
if(Type == OPENLONG || Type == OPENSHORT){ // 处理开仓
exchange.SetDirection(Type == OPENLONG ? "buy" : "sell")
var pfnOpen = Type == OPENLONG ? exchange.Buy : exchange.Sell
var idOpen = pfnOpen(Price, Amount, CurrPos, OnePriceTick, Type)
Sleep(TradeInterval)
if(idOpen) {
exchange.CancelOrder(idOpen)
} else {
CancelPendingOrders()
}
} else if(Type == COVERLONG || Type == COVERSHORT){ // 处理平仓
exchange.SetDirection(Type == COVERLONG ? "closebuy" : "closesell")
var pfnCover = Type == COVERLONG ? exchange.Sell : exchange.Buy
var idCover = pfnCover(Price, Amount, CurrPos, OnePriceTick, Type)
Sleep(TradeInterval)
if(idCover){
exchange.CancelOrder(idCover)
} else {
CancelPendingOrders()
}
} else {
throw "Type error:" + Type
}
}
function SuperTrend(r, period, multiplier) {
// atr
var atr = talib.ATR(r, period)
// baseUp , baseDown
var baseUp = []
var baseDown = []
for (var i = 0; i < r.length; i++) {
if (isNaN(atr[i])) {
baseUp.push(NaN)
baseDown.push(NaN)
continue
}
baseUp.push((r[i].High + r[i].Low) / 2 + multiplier * atr[i])
baseDown.push((r[i].High + r[i].Low) / 2 - multiplier * atr[i])
}
// fiUp , fiDown
var fiUp = []
var fiDown = []
var prevFiUp = 0
var prevFiDown = 0
for (var i = 0; i < r.length; i++) {
if (isNaN(baseUp[i])) {
fiUp.push(NaN)
} else {
fiUp.push(baseUp[i] < prevFiUp || r[i - 1].Close > prevFiUp ? baseUp[i] : prevFiUp)
prevFiUp = fiUp[i]
}
if (isNaN(baseDown[i])) {
fiDown.push(NaN)
} else {
fiDown.push(baseDown[i] > prevFiDown || r[i - 1].Close < prevFiDown ? baseDown[i] : prevFiDown)
prevFiDown = fiDown[i]
}
}
var st = []
var prevSt = NaN
for (var i = 0; i < r.length; i++) {
if (i < period) {
st.push(NaN)
continue
}
var nowSt = 0
if (((isNaN(prevSt) && isNaN(fiUp[i - 1])) || prevSt == fiUp[i - 1]) && r[i].Close <= fiUp[i]) {
nowSt = fiUp[i]
} else if (((isNaN(prevSt) && isNaN(fiUp[i - 1])) || prevSt == fiUp[i - 1]) && r[i].Close > fiUp[i]) {
nowSt = fiDown[i]
} else if (((isNaN(prevSt) && isNaN(fiDown[i - 1])) || prevSt == fiDown[i - 1]) && r[i].Close >= fiDown[i]) {
nowSt = fiDown[i]
} else if (((isNaN(prevSt) && isNaN(fiDown[i - 1])) || prevSt == fiDown[i - 1]) && r[i].Close < fiDown[i]) {
nowSt = fiUp[i]
}
st.push(nowSt)
prevSt = st[i]
}
var up = []
var down = []
for (var i = 0; i < r.length; i++) {
if (isNaN(st[i])) {
up.push(st[i])
down.push(st[i])
}
if (r[i].Close < st[i]) {
down.push(st[i])
up.push(NaN)
} else {
down.push(NaN)
up.push(st[i])
}
}
return [up, down]
}
var preTime = 0
function main() {
exchange.SetContractType(Symbol)
while (1) {
var r = _C(exchange.GetRecords)
var currBar = r[r.length - 1]
if (r.length < pd) {
Sleep(5000)
continue
}
var st = SuperTrend(r, pd, factor)
$.PlotRecords(r, "K")
$.PlotLine("L", st[0][st[0].length - 2], r[r.length - 2].Time)
$.PlotLine("S", st[1][st[1].length - 2], r[r.length - 2].Time)
if(!isNaN(st[0][st[0].length - 2]) && isNaN(st[0][st[0].length - 3])){
if (State == SHORT) {
State = COVERSHORT
} else if(State == IDLE) {
State = OPENLONG
}
}
if(!isNaN(st[1][st[1].length - 2]) && isNaN(st[1][st[1].length - 3])){
if (State == LONG) {
State = COVERLONG
} else if (State == IDLE) {
State = OPENSHORT
}
}
// 执行信号
var pos = null
var price = null
if(State == OPENLONG){ // 开多仓
pos = GetPosition(PD_LONG) // 检查持仓
// 判断是不是 满足状态,如果满足 修改状态
if(pos[1] >= Amount){ // 持仓超过或者等于参数设置的 开仓量
Sleep(1000)
$.PlotFlag(currBar.Time, "开多仓", 'OL') // 标记
OpenAmount = pos[1] // 记录开仓数
State = LONG // 标记为 做多状态
continue
}
price = currBar.Close - (currBar.Close % PriceTick) + PriceTick * 2 // 计算价格
Trade(OPENLONG, price, Amount - pos[1], pos, PriceTick) // 下单函数 (Type, Price, Amount, CurrPos, PriceTick)
}
if(State == OPENSHORT){ // 开空仓
pos = GetPosition(PD_SHORT) // 检查持仓
if(pos[1] >= Amount){
Sleep(1000)
$.PlotFlag(currBar.Time, "开空仓", 'OS')
OpenAmount = pos[1]
State = SHORT
continue
}
price = currBar.Close - (currBar.Close % PriceTick) - PriceTick * 2
Trade(OPENSHORT, price, Amount - pos[1], pos, PriceTick)
}
if(State == COVERLONG){ // 处理平多仓
pos = GetPosition(PD_LONG) // 获取持仓信息
if(pos[1] == 0){ // 判断持仓是否为 0
$.PlotFlag(currBar.Time, "平多仓", '----CL') // 标记
State = IDLE
continue
}
price = currBar.Close - (currBar.Close % PriceTick) - PriceTick * 2
Trade(COVERLONG, price, pos[1], pos, PriceTick)
}
if(State == COVERSHORT){ // 处理做多仓
pos = GetPosition(PD_SHORT)
if(pos[1] == 0){
$.PlotFlag(currBar.Time, "平空仓", '----CS')
State = IDLE
continue
}
price = currBar.Close - (currBar.Close % PriceTick) + PriceTick * 2
Trade(COVERSHORT, price, pos[1], pos, PriceTick)
}
if(State == COVERLONG_PART) { // 部分平多仓
pos = GetPosition(PD_LONG) // 获取持仓
if(pos[1] <= KeepAmount){ // 持仓小于等于 保持量,本次平仓完成
$.PlotFlag(currBar.Time, "平多仓,保留:" + KeepAmount, '----CL') // 标记
State = pos[1] == 0 ? IDLE : LONG // 更新状态
continue
}
price = currBar.Close - (currBar.Close % PriceTick) - PriceTick * 2
Trade(COVERLONG, price, pos[1] - KeepAmount, pos, PriceTick)
}
if(State == COVERSHORT_PART){
pos = GetPosition(PD_SHORT)
if(pos[1] <= KeepAmount){
$.PlotFlag(currBar.Time, "平空仓,保留:" + KeepAmount, '----CS')
State = pos[1] == 0 ? IDLE : SHORT
continue
}
price = currBar.Close - (currBar.Close % PriceTick) + PriceTick * 2
Trade(COVERSHORT, price, pos[1] - KeepAmount, pos, PriceTick)
}
LogStatus(_D())
Sleep(1000)
}
}
戦略アドレスは:https://www.fmz.com/strategy/201837
パラメータ設定,K線周期,参照: homily 大神スーパートレンド V.1 - スーパートレンドラインシステムK線サイクルは15分セット,スーパートレンドパラメータは45,3セット. OKEXフューチャークォーターコントラクトの過去1年の時間を回転し,取引ごとに1つのコントラクトをセットします.
戦略は学ぶためのもので,実際は慎重に使う.
リジングXfdjこの戦略の問題は解決したのでしょうか? このTVにはTA.superstendのポリシーがありますが,JavaScriptを書く方が自由です.
1070278998@qq.comこの関数は,f を求めるときに,f を求めます. この関数は,f を求めるときに,f を求めます.
スカイフਾਇਰ夢は強暴だ
ヴァイオリンテレビの差は,fmzのパッケージのATR計算の問題であるべきである.例えば,入力周期が7である.ATRの最初の6つの値は0であるべきだと計算した.しかし,実際には0ではありません.
発明者 量化 - 微かな夢現在,PINE スクリプトの関数を直接呼び出すことはできず,後期に互換性サポートが追加される可能性があります.
発明者 量化 - 微かな夢$.PlotLineは,図線クラスデータベースのインターフェース関数であり,この模板を策略広場にコピーすることができます.コードは公開されています.ソースコードを見て理解できます.
1070278998@qq.com$PlotRecords (r, "K") $.PlotLine (("L", st[0][st[0].length - 2],r[r.length - 2].Time) $.PlotLine (("S", st[1][st[1].length - 2],r[r.length - 2].Time) このLの後ろのコードは何を意味するのか? もしLが低線である場合,このLが出現する時間を示すために,このRが一緒に使用される必要がありますか?
1070278998@qq.com$PlotRecords ((r, "K") について $.PlotLine (("L", st[0][st[0].length - 2], r[r.length - 2].Time) $.PlotLine (("S", st[1][st[1].length - 2],r[r.length - 2].Time) このLの後ろのコードは何を表すのか? もし,このLの後ろのコードが,このLの後ろのRが,このLの後ろのコードと関わっていなければならない場合,
発明者 量化 - 微かな夢- 何のこと?
発明者 量化 - 微かな夢up[up.length - 1],指標の分数の最初のデータ,K線分数の最初のBARに対応する.
1070278998@qq.com周期を定義するには,どのパラメータを修正する必要がありますか.
1070278998@qq.com Up.length-1就是上边线最近的一个数字吗
発明者 量化 - 微かな夢2次元配列を返します. 上は上線,下は下線です. すべての指標データを返します.
発明者 量化 - 微かな夢詳細については,下記のTradingViewのアルゴリズムについて調べます.
ヴァイオリンはい,大
発明者 量化 - 微かな夢これは,Talib の ATR を使っているので,計算が正しくないようで,ATR を直接実行するアルゴリズムによるデータも少し違います.