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)
}
}
파라미터 설정, K 라인 주기, 참조: homily 대 신슈퍼트렌드 V.1 - 슈퍼트렌드 라인 시스템K 라인 사이클을 15분으로 설정하고, 슈퍼트렌드 매개 변수를 45.3로 설정한다. OKEX 퓨처스 쿼터 계약의 최근 1년 시간을 거슬러 올라가, 거래 당 1개 계약을 설정한다. 거래 당 1개 계약을 설정하기 때문에 자금 활용률이 낮아서 샤프가 중요하지 않다.
이 전략은 학습에만 쓰이고 실제 사용에는 주의해야 합니다.
리징 엑스
1070278998@qq.com알고리즘 return (up,down) 의 의미는 무엇이고, 반환된 내용이 어떻게 생겼는지, 슈퍼트렌드는 숫자가 아닌가요?
스카이프파이어꿈은 거칠다
비올라인TV에 있는 차이점은 fmz 포장에 있는 ATR 계산 문제와 같아야 합니다. 예를 들어, 입력 주기는 7이고, 계산된 ATR의 첫 번째 6값은 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 뒤에 있는 코드가 무엇을 의미하는지 물어보세요. 만약 이것이 하위선이라면, r 뒤에 있는 코드가 무엇을 의미할까요?
발명가들의 수량화 - 작은 꿈무슨'sp'?
발명가들의 수량화 - 작은 꿈up[up.length - 1], 지표의 음수 첫 번째 데이터, K선 음수 첫 번째 BAR와 대응한다.
1070278998@qq.com어떻게 sp의 주기를 결정하고 어떤 변수를 변경해야 하는지
1070278998@qq.com Up.length-1就是上边线最近的一个数字吗
발명가들의 수량화 - 작은 꿈2차원 배열을 반환합니다. 위는 위의 줄이고 아래는 아래의 줄입니다. 전체 지표 데이터를 반환합니다.
발명가들의 수량화 - 작은 꿈자, 트레이딩뷰에 있는 알고리즘을 자세히 살펴보겠습니다.
비올라인네,
발명가들의 수량화 - 작은 꿈좋아요, 감사합니다, 하지만 저는 Talib의 ATR을 사용하고 있습니다. 계산이 제대로 된 것 같지는 않습니다.