价格振幅均线-3年33万倍收益

Author: xiaode123, Date: 2023-03-23 14:02:44
Tags:


/*backtest
start: 2020-01-01 00:00:00
end: 2023-03-24 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"ETH_USDT","fee":[0.018,0.036]}]
*/

//地址https://www.fmz.com/strategy/405725

const QuotePrecision = 10;//下单价格精度
const BasePrecision = 10;//下单量精度

const long = 'long';//做多-期货
const closelong = 'closelong';//做多-平仓
const short = 'short';//做空-期货
const closeshort = 'closeshort';//做空-平仓
const isTest = true;//是不是币安测试API

const minPriceNum = 2;//保留几位小数点(买卖价格最低设置类似1660.17usdt)
const marginLevel = 1;//杆杠大小

let lastKLineTime = 0;//最后一个结束的k线时间戳(比如现在10:30,那就是9点时间戳)

const priceAdd = 0.01;//交易时改变1%设置价格
let lastOrderTime = 0;//最后一次下订单时间戳-秒

const serviceCharge = 0.0004;//手续费0.04%
let signalData = {};//订单数据-用于订单交易成功时使用
let maintMarginPro = 0.005;//维持保证金比率0.50%
let maintMarginNum = 0;//维持保证金速算额 (USDT)

const cfgName1 = "k线图表";
var registerInfo = {};
var chart = null;
var arrCfg = [];
const maxBufferLen = 10;//

let beginMoney = 0;//启动时的总资产
let exchangeNum = 0;//本次交易次数(开仓+平仓算2次)
const lastNumPro_MarketPrice = 0.02;//因为用市价不好把握价格,空间留大点
const buyMinPro = 0.02;//剩余钱不到总钱2%,不操作,避免小额交易

let period = 0;//K线周期-秒

const atrNum = 6;
const stopKLineNum = 0;//出现止损,休息()个K线
const pp = 12;//数值越大,格子差距越小
const StopGrid = 16;//止损网格价格倍数

let lastStopTime = 0;

const checkTime = 1500;//每隔多少秒检测一下代码-1小时
let lastCheckTime = 0;//上次检测时间戳-秒

let currency;
let nowMarkPrice = 0;
let nowPosition;
let nowAccount;

function main() {
    testLog("调用main");
    let extension = {
        layout: 'single',//single:图表不会叠加(不会以分页标签方式显示),会单独显示(平铺显示),默认为分组 'group'
        col: 12,//设置图表的页面宽度,1-12
        height: '700px'//图表的高度
    }
    Sleep(1000);

    while (true) {
        setNowData();
        let bars = _C(exchange.GetRecords);//只能获得最近300个周期的数据?
        PlotMultRecords(bars, cfgName1, "k线", extension);//画k线图
        drawLine(bars);//画sma线,策略

        Sleep(1000 * 10);//每秒运行下代码
    }

}

/** 活动最新数据 */
function setNowData() {
    setMarkPrice();
    setNowPosition();
    setNowAccount();
}

// 初始化函数
function init() {
    _CDelay(1000 * 10);// 调整_C()函数重试时间间隔为n秒

    testLog("初始化!");
    // 设置精度(小数点位数,回测不支持)
    exchange.SetPrecision(QuotePrecision, BasePrecision);

    exchange.SetContractType("swap");//永续合约
    if (isTest) {
        exchange.SetBase("https://testnet.binancefuture.com");// 切换为测试的地址
    }
    let arr = exchange.GetCurrency().split('_');//ETH_USDT=>ETH_USDT
    currency = arr[0] + arr[1];
    Log('交易对:' + currency);

    setNowData();
    log_ticker("初始化");
    log_account("初始化");

    beginMoney = getAllMoney();

    chart = Chart(arrCfg);

    period = _C(exchange.GetPeriod);//K线周期
    let periodTxt = getTimeTxt(period);
    testLog("K线周期:" + periodTxt);
}


/** 画sma均线 */
function drawLine(bars) {
    // 使用现货交易所对象测试,获取K线数据。如果使用期货交易所对象测试,需要先设置合约
    if (!bars) {
        return;
    }

    if (lastKLineTime == 0) {//第一次启动,从头开始
        var begin = atrNum - 1;
    } else {
        begin = bars.length - 2;//理论上只看最新一个数据就行,但为了防止误差,看2个
    }
    if (begin < 0) {
        return;
    }

    let atr = talib.ATR(bars, atrNum);//计算平均价格振幅

    for (let i = begin; i < bars.length; i++) {
        let bar = bars[i];
        if (bar.Time <= lastKLineTime) {//已经计算、画图过的
            continue;
        }

        let avg_pra = atr[i] / bar.Close

        let hl2 = (bar.High + bar.Low) / 2;
        //计算网格
        let grid = hl2 * avg_pra / pp;
        let p1 = hl2 + grid * StopGrid;
        let p2 = hl2 + grid * 2;
        let p0 = hl2;
        let p3 = hl2 - grid * 2;
        let p4 = hl2 - grid * StopGrid;

        //------------画k线图等
        if (i < bars.length - 1) {
            lastKLineTime = bar.Time;
            //最后一条数据不完整,结束画
            PlotMultLine(cfgName1, "p1", p1, bar.Time, '#FF9800');
            PlotMultLine(cfgName1, "p2", p2, bar.Time, '#265ec5');
            PlotMultLine(cfgName1, "p0", p0, bar.Time, '#7c7c7c');
            PlotMultLine(cfgName1, "p3", p3, bar.Time, '#265ec5');
            PlotMultLine(cfgName1, "p4", p4, bar.Time, '#FF9800');
            continue;
        }

        //------------以最后一条数据获得的sma值进行交易判断(for循环只进最后一次)
        // ======================== 策略操作 - 开始 ============================
        if (hasOrder()) {//有未完成的订单
            return;
        }

        let nowTime = getNowTime();
        if ((lastCheckTime + checkTime) <= nowTime) {
            lastCheckTime = nowTime;//每隔多少秒检测一下代码
        } else {
            return;
        }

        if ((lastStopTime + stopKLineNum * period * 1000) > bar.Time) {
            return;
        }

        //只做多
        if (bar.Close < p4) {
            let funTxt = 'Fun_止损';
            let isSuccess = ExchangeFun(closelong, funTxt);
            if (isSuccess) {
                lastStopTime = bar.Time;
            }
        } else if (bar.Close < p3) {
            let funTxt = 'Fun_做多';
            ExchangeFun(long, funTxt);
        } else if (bar.Close > p2) {
            let funTxt = 'Fun_止盈';
            ExchangeFun(closelong, funTxt);
        }
    }
}


/** 有没有未完成的订单 */
function hasOrder() {
    let orders = _C(exchange.GetOrders);//获取所有未完成的订单
    if (!orders) {
        return true;
    }
    if (orders.length == 0 && signalData && signalData.FunTxt) {
        let order = _C(exchange.GetOrder, signalData.Id);
        if (order) {
            exchangeNum++;
            let nowTime = getNowTime();

            let timeTxtxt = getTimeTxt(nowTime - lastOrderTime);
            let txt = signalData.FunTxt + ',报价:' + order.Price + ',均价:' + order.AvgPrice
                + ',量:' + order.Amount + '%' + ",次数:" + exchangeNum
                + ",Action:" + signalData.Action + ",耗时:" + timeTxtxt;
            Log("end订单成功----" + txt);
            log_account("end----");
            PlotMultFlag(cfgName1, "flag1", new Date().getTime(), txt, signalData.FunTxt);
            signalData = {};
        }
    }
    if (orders.length > 0) {
        return true;
    } else {
        return false;
    }
}



//做多做空等实际功能
function ExchangeFun(action, funTxt, percent = 1) {
    let amount;
    let tradeInfo;
    let markPrice = getMarkPrice();//标记价格
    if (action == long || action == closeshort) {//买
        var price = markPrice * (1 + priceAdd);
    } else if (action == short || action == closelong) {//卖
        price = markPrice * (1 - priceAdd);
    }
    price = _floor(markPrice, minPriceNum);

    let min = getMinNum();//eth最小操作0.001个
    if (action == long) {//做多
        if (!canBuy()) {//避免小额交易
            return false;
        }
        amount = getBuyNum(price, 0);//购买多少个eth
        if (amount >= min) {
            beginTrans();
            exchange.SetMarginLevel(marginLevel);//设置杆杠大小
            exchange.SetDirection("buy");
            tradeInfo = exchange.Buy(-1, amount);//市价
        }
    } else if (action == short) {//做空
        if (!canBuy()) {//避免小额交易
            return false;
        }
        amount = getBuyNum(price, 1);//做空卖多少个eth
        if (amount >= min) {
            beginTrans();
            exchange.SetMarginLevel(marginLevel);//设置杆杠大小
            exchange.SetDirection("sell");
            tradeInfo = exchange.Sell(-1, amount);
        }
    } else if (action == closelong) {//平仓-做多
        amount = getCoinNum(0) * percent;//卖掉多少个期货eth
        if (amount >= min) {
            beginTrans();
            exchange.SetDirection("closebuy");
            tradeInfo = exchange.Sell(-1, amount);
        }
    } else if (action == closeshort) {//平仓-做空
        amount = getCoinNum(1) * percent;
        if (amount >= min) {
            beginTrans();
            exchange.SetDirection("closesell");
            tradeInfo = exchange.Buy(-1, amount);
        }
    }

    if (tradeInfo) {
        signalData = { 'Action': action, 'Id': tradeInfo, 'FunTxt': funTxt };
        log_ticker("end----,订单Action:" + action + ",price:" + price);
        return true;
    }
    return false;
}


/** 开始交易 */
function beginTrans() {
    lastOrderTime = getNowTime();
    log_account("bengin----");
}

function log_account(txt) {
    let acc = GetAcc();
    let markPrice = getMarkPrice();

    testLog(txt + ",可用余额:" + acc.Balance + ",标记价格:" + markPrice + ",账户:" + JSON.stringify(acc));

    let position = getNowPosition();
    if (position.length > 0) {
        let data = position[0];//默认持仓就1个
        let typeTxt = '';
        if (data.Type == 0) {
            typeTxt = '做多';
        } else if (data.Type == 1) {
            typeTxt = '做空';
        }
        let leverageTxt = '';
        if (data.Info) {//回测时没有?
            leverageTxt = ",杠杆:" + data.Info.leverage;
        }
        testLog("持仓信息 eth:" + data.Amount + ",Price:" + data.Price
            // , ",利润:", data.Profit
            + ",Type:" + typeTxt + leverageTxt + ",详情:" + JSON.stringify(data));
    }
}

/** 获得账号信息 */
function GetAcc() {
    return nowAccount;
}
/** 设置账号信息 */
function setNowAccount() {
    let acc = _C(exchange.GetAccount);
    if (acc.Info) {
        acc.Info.assets = null;
        acc.Info.positions = null;
    }
    nowAccount = acc;
}

function log_ticker(txt) {
    testLog(txt);
}



/** 预计可以购买多少个eth 0做多,1做空 */
function getBuyNum(price, type) {
    let acc = GetAcc();
    let balance = acc.Balance;//有多少usdt
    if (balance < 100000) {
        maintMarginPro = 0.005;//维持保证金比率
        maintMarginNum = 0;//维持保证金速算额 (USDT)
    } else if (balance < 250000) {
        maintMarginPro = 0.0065;
        maintMarginNum = 150;
    } else if (balance < 2000000) {
        maintMarginPro = 0.01;
        maintMarginNum = 1025;
    } else if (balance < 10000000) {
        maintMarginPro = 0.02;
        maintMarginNum = 21025;
    } else {
        //暂不处理
    }
    balance -= maintMarginNum;

    let markPrice = getMarkPrice();//标记价格
    let lossType;//开仓亏损:订单方向
    //尽量多买,避免小额多次交易
    if (type == 0) {//做多
        lossType = 1;
    } else if (type == 1) {//做空
        lossType = -1;
    }
    if (type == 0) {//做多
        var usePrice = price;
    } else if (type == 1) {//做空
        usePrice = Math.max(price, markPrice);
    }

    // 开仓亏损=合约数量* 绝对值{min[0, 订单方向* (标记价格- 订单价格)]}
    let losePro = Math.abs(Math.min(0, lossType * (markPrice - price)));

    // 订单价格: 限价单:我挂的价格 市价单:卖一
    // 买单(做多),最大可用资金可用/{订单价格/杠杆倍数+绝对值(min0,标记价格-订单价格)}
    // 卖单(做空),最大可用资金可用/{max(标记价,订单价格)/杠杆倍数+绝对值(min0,订单价格-标记价)}
    let amount = balance / (usePrice / marginLevel + losePro);//计算开仓亏损

    //扣的钱按全部购买算
    amount /= (1 + serviceCharge);//计算手续费
    amount /= (1 + maintMarginPro);//计算维持保证金
    amount *= (1 - lastNumPro_MarketPrice);//保留点
    amount = _floor(amount);

    return amount;
}

/** 期货仓库里有多少个eth,type:0做多的仓,1做空的仓 */
function getCoinNum(type) {
    var position = getNowPosition();
    if (position.length > 0) {
        let data = position[0];//默认持仓就1个
        // let num = _floor(data.Amount);
        let num = data.Amount;
        if (data.Type == type) {
            return num;
        }
    }
    return 0;
}


/** 剩余钱不到总钱2%,不操作,避免小额交易 */
function canBuy() {
    var position = getNowPosition();
    if (position.length > 0) {
        let acc = GetAcc();
        let allMoney = getAllMoney();
        if (acc.Balance / allMoney < (buyMinPro + maintMarginPro)) {
            return false;
        }
    }
    return true;
}

/** 估计当前总资产 */
function getAllMoney() {
    let acc = GetAcc();
    let allMoney = acc.Balance;//可用余额
    allMoney += acc.FrozenBalance;//冻结余额
    var position = getNowPosition();
    if (position.length > 0) {
        let data = position[0];//默认持仓就1个
        let markPrice = getMarkPrice();

        if (data.Type == 0) {//做多
            allMoney += data.Amount * markPrice;
        } else if (data.Type == 1) {//做空
            allMoney += data.Amount * data.Price;//做空前的本金
            allMoney += (data.Price - markPrice) * data.Amount;//做空的收益
        }
    }
    return allMoney;
}


/** 获得标记价格 */
function getMarkPrice() {
    return nowMarkPrice;
}
/** 获得标记价格 */
function setMarkPrice() {
    //模拟回测
    let ticker = _C(exchange.GetTicker);//获得行情数据最多10分钟
    nowMarkPrice = ticker.Last;//最后一次交易价格
}

/** 最少买0.001个eth */
function getMinNum() {
    return 0.001;
}

/** 向下取整,保留3位小数点(开仓手数:最低设置0.001个ETH) */
function _floor(num, min = 3) {
    num = Math.floor(num * Math.pow(10, min)) / Math.pow(10, min);
    num = parseFloat(num);//string转Float
    return num;
}

/** 返回当前时间戳-秒 */
function getNowTime() {
    return Unix();
}

/** 画k线图 */
function PlotMultRecords(bars, cfgName, seriesName, extension) {
    var index = -1;
    var eleIndex = -1;

    do {
        var cfgInfo = registerInfo[cfgName];
        if (typeof (cfgInfo) == "undefined") {
            var cfg = {
                name: cfgName,
                __isStock: true,
                title: {
                    text: cfgName
                },
                tooltip: {
                    xDateFormat: '%Y-%m-%d %H:%M:%S, %A'
                },
                legend: {
                    enabled: true,
                },
                plotOptions: {
                    candlestick: {
                        color: '#d75442',
                        upColor: '#6ba583'
                    }
                },
                rangeSelector: {
                    buttons: [{
                        type: 'hour',
                        count: 1,
                        text: '1h'
                    }, {
                        type: 'hour',
                        count: 3,
                        text: '3h'
                    }, {
                        type: 'hour',
                        count: 8,
                        text: '8h'
                    }, {
                        type: 'all',
                        text: 'All'
                    }],
                    selected: 2,
                    inputEnabled: true
                },
                series: [{
                    type: 'candlestick',
                    name: seriesName,
                    id: seriesName,
                    data: []
                }],
            }

            if (typeof (extension) != "undefined") {
                cfg.extension = extension;
            }

            registerInfo[cfgName] = {
                "cfgIdx": arrCfg.length,
                "seriesIdxs": [{
                    seriesName: seriesName,
                    index: arrCfg.length,
                    type: "candlestick",
                    preBarTime: 0
                }],
            };
            arrCfg.push(cfg);
            updateSeriesIdx();
        }

        chart.update(arrCfg);//刷新所有图表

        _.each(registerInfo[cfgName].seriesIdxs, function (ele, i) {
            if (ele.seriesName == seriesName && ele.type == "candlestick") {
                index = ele.index;
                eleIndex = i;
            }
        });
        if (index == -1) {
            arrCfg[registerInfo[cfgName].cfgIdx].series.push({
                type: 'candlestick',
                name: seriesName,
                id: seriesName,
                data: []
            });
            registerInfo[cfgName].seriesIdxs.push({
                seriesName: seriesName,
                index: arrCfg.length,
                type: "candlestick",
                preBarTime: 0
            });
            updateSeriesIdx();
        }
    } while (index == -1)

    for (var i = 0; i < bars.length; i++) {
        let bar = bars[i];
        let data = [bar.Time, bar.Open, bar.High, bar.Low, bar.Close];//写入图表的一个周期数据
        let preBarTime = registerInfo[cfgName].seriesIdxs[eleIndex].preBarTime;
        if (bar.Time == preBarTime) {
            chart.add(index, data, -1);//更新当前周期
        } else if (bar.Time > preBarTime) {
            registerInfo[cfgName].seriesIdxs[eleIndex].preBarTime = bar.Time
            chart.add(index, data);//添加历史(不变了)
        }
    }

}

function updateSeriesIdx() {
    var index = 0
    var map = {}
    _.each(arrCfg, function (cfg) {
        _.each(cfg.series, function (series) {
            var key = cfg.name + "|" + series.name
            map[key] = index
            index++
        })
    })

    for (var cfgName in registerInfo) {
        _.each(arrCfg, function (cfg, cfgIdx) {
            if (cfg.name == cfgName) {
                registerInfo[cfgName].cfgIdx = cfgIdx
            }
        })

        for (var i in registerInfo[cfgName].seriesIdxs) {
            var seriesName = registerInfo[cfgName].seriesIdxs[i].seriesName
            var key = cfgName + "|" + seriesName
            if (typeof (map[key]) != "undefined") {
                registerInfo[cfgName].seriesIdxs[i].index = map[key]
            }

            if (registerInfo[cfgName].seriesIdxs[i].type == "candlestick") {
                registerInfo[cfgName].seriesIdxs[i].preBarTime = 0
            } else if (registerInfo[cfgName].seriesIdxs[i].type == "line") {
                registerInfo[cfgName].seriesIdxs[i].preDotTime = 0
            } else if (registerInfo[cfgName].seriesIdxs[i].type == "flag") {
                registerInfo[cfgName].seriesIdxs[i].preFlagTime = 0
            }
        }
    }

    if (!chart) {
        chart = Chart(arrCfg)
    }
    chart.update(arrCfg)
    chart.reset()

    _G("registerInfo", registerInfo)
    _G("arrCfg", arrCfg)

    for (var cfgName in registerInfo) {
        for (var i in registerInfo[cfgName].seriesIdxs) {
            var buffer = registerInfo[cfgName].seriesIdxs[i].buffer
            var index = registerInfo[cfgName].seriesIdxs[i].index
            if (buffer && buffer.length != 0 && registerInfo[cfgName].seriesIdxs[i].type == "line" && registerInfo[cfgName].seriesIdxs[i].preDotTime == 0) {
                _.each(buffer, function (obj) {
                    chart.add(index, [obj.ts, obj.dot])
                    registerInfo[cfgName].seriesIdxs[i].preDotTime = obj.ts
                })
            } else if (buffer && buffer.length != 0 && registerInfo[cfgName].seriesIdxs[i].type == "flag" && registerInfo[cfgName].seriesIdxs[i].preFlagTime == 0) {
                _.each(buffer, function (obj) {
                    chart.add(index, obj.data)
                    registerInfo[cfgName].seriesIdxs[i].preFlagTime = obj.ts
                })
            }
        }
    }
}


function checkBufferLen(buffer, maxLen) {
    while (buffer.length > maxLen) {
        buffer.shift()
    }
}

/** 画线条 */
function PlotMultLine(cfgName, seriesName, dot, ts, color, extension) {
    var index = -1;
    var eleIndex = -1;

    do {
        var cfgInfo = registerInfo[cfgName]
        if (typeof (cfgInfo) == "undefined") {
            var cfg = {
                name: cfgName,
                __isStock: true,
                title: {
                    text: cfgName
                },
                xAxis: {
                    type: 'datetime'
                },
                series: [{
                    type: 'line',
                    name: seriesName,
                    id: seriesName,
                    color: color,
                    data: [],
                }]
            };

            if (extension) {
                cfg.extension = extension;
            }

            registerInfo[cfgName] = {
                "cfgIdx": arrCfg.length,
                "seriesIdxs": [{
                    seriesName: seriesName,
                    index: arrCfg.length,
                    type: "line",
                    color: color,
                    buffer: [],
                    preDotTime: 0
                }],
            };
            arrCfg.push(cfg);
            updateSeriesIdx();
        }

        chart.update(arrCfg);

        _.each(registerInfo[cfgName].seriesIdxs, function (ele, i) {
            if (ele.seriesName == seriesName && ele.type == "line") {
                index = ele.index;
                eleIndex = i;
            }
        })
        if (index == -1) {
            arrCfg[registerInfo[cfgName].cfgIdx].series.push({
                type: 'line',
                name: seriesName,
                id: seriesName,
                color: color,
                data: [],
            });
            registerInfo[cfgName].seriesIdxs.push({
                seriesName: seriesName,
                index: arrCfg.length,
                type: "line",
                color: color,
                buffer: [],
                preDotTime: 0
            });
            updateSeriesIdx();
        }
    } while (index == -1)

    if (typeof (ts) == "undefined") {
        ts = new Date().getTime();
    }

    var buffer = registerInfo[cfgName].seriesIdxs[eleIndex].buffer;
    if (registerInfo[cfgName].seriesIdxs[eleIndex].preDotTime != ts) {
        registerInfo[cfgName].seriesIdxs[eleIndex].preDotTime = ts;
        chart.add(index, [ts, dot]);
        buffer.push({
            ts: ts,
            dot: dot
        });
        checkBufferLen(buffer, maxBufferLen);
    } else {
        chart.add(index, [ts, dot], -1);
        buffer[buffer.length - 1].dot = dot;
    }

}

/** 画flag */
function PlotMultFlag(cfgName, seriesName, ts, text, title, shape, color, onSeriesName) {
    if (typeof (cfgName) == "undefined" || typeof (registerInfo[cfgName]) == "undefined") {
        throw "need cfgName!";
    }

    var index = -1;
    var eleIndex = -1;

    do {
        chart.update(arrCfg);

        _.each(registerInfo[cfgName].seriesIdxs, function (ele, i) {
            if (ele.seriesName == seriesName && ele.type == "flag") {
                index = ele.index;
                eleIndex = i;
            }
        });
        if (index == -1) {
            arrCfg[registerInfo[cfgName].cfgIdx].series.push({
                type: 'flags',
                name: seriesName,
                onSeries: onSeriesName || arrCfg[registerInfo[cfgName].cfgIdx].series[0].id,
                data: []
            });
            registerInfo[cfgName].seriesIdxs.push({
                seriesName: seriesName,
                index: arrCfg.length,
                type: "flag",
                buffer: [],
                preFlagTime: 0
            });
            updateSeriesIdx();
        }
    } while (index == -1)

    if (typeof (ts) == "undefined") {
        ts = new Date().getTime();
    }

    var buffer = registerInfo[cfgName].seriesIdxs[eleIndex].buffer;
    var obj = {
        x: ts,
        color: color,
        shape: shape,
        title: title,
        text: text
    };
    if (registerInfo[cfgName].seriesIdxs[eleIndex].preFlagTime != ts) {
        registerInfo[cfgName].seriesIdxs[eleIndex].preFlagTime = ts;
        chart.add(index, obj);
        buffer.push({
            ts: ts,
            data: obj
        });
        checkBufferLen(buffer, maxBufferLen);
    } else {
        chart.add(index, obj, -1);
        buffer[buffer.length - 1].data = obj;
    }

}



function testLog(txt) {
    Log(txt);
}

function getNowPosition() {
    return nowPosition;
}
function setNowPosition() {
    nowPosition = _C(exchange.GetPosition);
}

/** 把时间秒改成天\小时等 */
function getTimeTxt(time) {
    if (time < 60) {
        var timeTxt = time;
        var key = '秒';
    } else if (time < 3600) {
        timeTxt = time / 60;
        key = '分钟';
    } else if (time < 3600 * 24) {
        timeTxt = time / 3600;
        key = '小时';
    } else {
        timeTxt = time / 3600 / 24;
        key = '天';
    }
    timeTxt = Math.floor(timeTxt * 10) / 10 + key;//保留1位小数点
    return timeTxt;
}

More

sxj3388 回测漂亮,实盘亏?

kuailefeng2020 回测K线精度不够,所以跑出来效果很好,实际你用5分钟k线,精度比D1的k线精度高得多,测试下来净是亏。

如我初来 使用这个进行回测之后。开始较为稳定的亏损了 /*backtest start: 2022-04-19 00:00:00 end: 2023-04-21 00:00:00 period: 1h basePeriod: 1m exchanges: [{"eid":"Futures_Binance","currency":"LTC_USDT","balance":200,"fee":[0.02,0.04],"balance":1000}] */

如我初来 不少变量的初始化感觉有点怪,例如下面的。。强迫症选手,看着难受 if (type == 0) {//做多 var usePrice = price; } else if (type == 1) {//做空 usePrice = Math.max(price, markPrice); }

xiaode123 直接跑3年会报错,大概是市场不够了 如果一年年来 20-21年,收益49倍 21-22年,收益232倍 22-2023-03-24年,收益89倍 一共100万倍,更吓人了😅

xiaode123 加了isTest,可以去币安测试网实盘了(本人就跑了一会,出bug是正常的)

xiaode123 这是回测版本,实盘的币安测试网和正式的没去调,因为我不信这数据,就没去改了

xiaode123 fmz回测年化10w倍收益,太吓人,怀疑是fmz回测机制恰好碰到我的代码,出bug了,真拿去跑别怪我啊!!!

sxj3388 有时候没按规则来好象,没单子后c>p2也在做多,c<p3时多单也没止损,原因好象是实时盘中的p2,p3位置变高了.这个策略主做振荡行情,因为大多数时间是振荡。可另配一个趋势策略互补。

xiaode123 Fun_做多就是开仓,止盈止损就是平仓

sxj3388 开平仓规则是哪几行代码?没搞懂。

xiaode123 反正跑一会效果没这么明显

如我初来 我猜也是很奇怪的问题导致的, 准备翻译成java,本地回测下