const logger = require("./utils/logger"); const NumKit = require('./utils/num-kit') const TimeKit = require('./utils/time-kit') const fs = require('fs').promises; async function readData() { let data = await fs.readFile('./data/k_lines.json', 'utf8') return JSON.parse(data) } let realCountMap = {} function getRealDragonMap(kLinesMap, FIRST_FEW_DAYS, BUY_LIMIT_RATE) { let realDragonMap = {} for (let symbol in kLinesMap) { let kLines = kLinesMap[symbol] let index = kLines.length - (FIRST_FEW_DAYS + 1) let kLine = kLines[index] let prevKline = kLines[index - 1] // 开盘第一天不计算 if (!kLine || !prevKline) continue let rate = 100 * (kLine.Close - kLine.Open) / kLine.Open if (rate > BUY_LIMIT_RATE) { kLine.Rate = rate kLine.Profit = rate - BUY_LIMIT_RATE realDragonMap[symbol] = kLine if (!realCountMap[symbol]) { realCountMap[symbol] = kLine.Profit } else { realCountMap[symbol] += kLine.Profit } realCountMap[symbol] = NumKit.getSubFloat(realCountMap[symbol], 2) } } return realDragonMap } let fakeCountMap = {} function getFakeDragonMap(kLinesMap, FIRST_FEW_DAYS, BUY_LIMIT_RATE) { let fakeDragonMap = {} for (let symbol in kLinesMap) { let kLines = kLinesMap[symbol] let index = kLines.length - (FIRST_FEW_DAYS + 1) let kLine = kLines[index] let prevKline = kLines[index - 1] // 开盘第一天不计算 if (!kLine || (!prevKline)) continue let rate = 100 * (kLine.Close - kLine.Open) / kLine.Open let maxRate = 100 * (kLine.High - kLine.Open) / kLine.Open if (maxRate > BUY_LIMIT_RATE && rate < BUY_LIMIT_RATE) { kLine.Rate = rate kLine.MaxRate = maxRate kLine.Profit = rate > 0 ? rate - BUY_LIMIT_RATE : -BUY_LIMIT_RATE fakeDragonMap[symbol] = kLine if (!fakeCountMap[symbol]) { fakeCountMap[symbol] = kLine.Profit } else { fakeCountMap[symbol] += kLine.Profit } fakeCountMap[symbol] = NumKit.getSubFloat(fakeCountMap[symbol], 2) } } return fakeDragonMap } // 统计单日涨幅大于5%的有多少根k线 // function statisticA(kLines, start, end) { // let count = 0 // // for (let i = start >= 0 ? start : 0; i <= end; i++) { // let kLine = kLines[i] // let upRate = NumKit.getSubFloat(100 * (kLine.Close - kLine.Open) / kLine.Open, 2) // // if (upRate > 5) { // count += 1 // } // } // // return count // } function dragonAnalysis(dragonMap) { } async function main() { let kLinesMap = await readData() const FIRST_FEW_DAYS = 1 // 第几天的数据,0表示今天,1表示昨天,2表示前天,以此类推 const BUY_LIMIT_RATE = 2.5 // 从什么比例入场 const BAKE_TEST_DAYS = 1 // 一共回测多少天 let totalProfit = 0 for (let i = FIRST_FEW_DAYS; i < FIRST_FEW_DAYS + BAKE_TEST_DAYS; i++) { // 赚钱榜 let realDragonProfit = 0 let realDragonMap = getRealDragonMap(kLinesMap, i, BUY_LIMIT_RATE) for (let symbol in realDragonMap) { realDragonProfit += realDragonMap[symbol].Profit // logger.info(realDragonMap[symbol].Symbol, realDragonMap[symbol].Profit, realDragonMap[symbol].Rate) } logger.info("----------------赚钱榜数据分析----------------") dragonAnalysis(realDragonMap) // 亏钱榜 let fakeDragonProfit = 0 let fakeDragonMap = getFakeDragonMap(kLinesMap, i, BUY_LIMIT_RATE) for (let symbol in fakeDragonMap) { fakeDragonProfit += fakeDragonMap[symbol].Profit // logger.info(fakeDragonMap[symbol].Symbol, fakeDragonMap[symbol].Profit, fakeDragonMap[symbol].MaxRate, fakeDragonMap[symbol].Rate) } logger.info("----------------亏钱榜数据分析----------------") dragonAnalysis(fakeDragonMap) realDragonProfit = NumKit.getSubFloat(realDragonProfit, 2) fakeDragonProfit = NumKit.getSubFloat(fakeDragonProfit, 2) let realLength = Object.keys(realDragonMap).length let fakeLength = Object.keys(fakeDragonMap).length let realRate = NumKit.getSubFloat(realLength / (realLength + fakeLength), 2) let fakeRate = NumKit.getSubFloat(1 - realRate, 2) let expRealProfit = NumKit.getSubFloat(realRate * realDragonProfit, 2) let expFakeProfit = NumKit.getSubFloat(fakeRate * fakeDragonProfit, 2) let synProfit = NumKit.getSubFloat(expFakeProfit + expRealProfit, 2) let avgProfit = NumKit.getSubFloat(synProfit / (realLength + fakeLength), 2) let index = kLinesMap['BTC_USDT'].length - (i + 1) let btcK = kLinesMap['BTC_USDT'][index] let dateStr = TimeKit.getDateByMillisecond(btcK.Time) let btcUpRate = NumKit.getSubFloat(100 * (btcK.Close - btcK.Open) / btcK.Open, 2) logger.info(`${i}日(${dateStr}, ${realLength + fakeLength}只),赚钱榜(${realLength}只)利润${realDragonProfit}%` + `,亏钱榜(${fakeLength}只)利润${fakeDragonProfit}%` + `,真龙期望利润${expRealProfit}%,假龙期望利润${expFakeProfit}%,综合利润${synProfit}%,平均每只利润${avgProfit}%,BTC涨幅${btcUpRate}%` ) totalProfit += avgProfit totalProfit = NumKit.getSubFloat(totalProfit, 2) } // let dayProfit = NumKit.getSubFloat(totalProfit / BAKE_TEST_DAYS, 2) // logger.info(`利润期望值总和:${totalProfit}%,平均日化${dayProfit}%。`) // for (let symbol in fakeCountMap) { // let kLines = kLinesMap[symbol] // let startIndex = kLines.length - BAKE_TEST_DAYS // let endIndex = kLines.length - 1 // // logger.info(`${symbol} 盈${realCountMap[symbol]},亏${fakeCountMap[symbol]},大于5%涨幅的共有${statisticA(kLines, startIndex, endIndex)}日。`) // } } main().catch((error) => { logger.error(error.stack); process.exitCode = 1; })