十面埋伏分析.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. const logger = require("./utils/logger");
  2. const NumKit = require('./utils/num-kit')
  3. const TimeKit = require('./utils/time-kit')
  4. const fs = require('fs').promises;
  5. async function readData() {
  6. let data = await fs.readFile('./data/k_lines.json', 'utf8')
  7. return JSON.parse(data)
  8. }
  9. let realCountMap = {}
  10. function getRealDragonMap(kLinesMap, dayCount, BUY_LIMIT_RATE) {
  11. let realDragonMap = {}
  12. for (let symbol in kLinesMap) {
  13. let kLines = kLinesMap[symbol]
  14. let index = kLines.length - (dayCount + 1)
  15. let kLine = kLines[index]
  16. let prevKline = kLines[index - 1]
  17. // 开盘第一天不计算
  18. if (!kLine || !prevKline) continue
  19. let rate = 100 * (kLine.Close - kLine.Open) / kLine.Open
  20. if (rate > BUY_LIMIT_RATE) {
  21. kLine.Rate = rate
  22. kLine.Profit = NumKit.getSubFloat(rate - BUY_LIMIT_RATE, 2)
  23. realDragonMap[symbol] = kLine
  24. if (!realCountMap[symbol]) {
  25. realCountMap[symbol] = kLine.Profit
  26. } else {
  27. realCountMap[symbol] += kLine.Profit
  28. }
  29. realCountMap[symbol] = NumKit.getSubFloat(realCountMap[symbol], 2)
  30. }
  31. }
  32. return realDragonMap
  33. }
  34. let fakeCountMap = {}
  35. function getFakeDragonMap(kLinesMap, dayCount, BUY_LIMIT_RATE) {
  36. let fakeDragonMap = {}
  37. for (let symbol in kLinesMap) {
  38. let kLines = kLinesMap[symbol]
  39. let index = kLines.length - (dayCount + 1)
  40. let kLine = kLines[index]
  41. let prevKline = kLines[index - 1]
  42. // 开盘第一天不计算
  43. if (!kLine || (!prevKline)) continue
  44. let rate = 100 * (kLine.Close - kLine.Open) / kLine.Open
  45. let maxRate = 100 * (kLine.High - kLine.Open) / kLine.Open
  46. if (maxRate > BUY_LIMIT_RATE && rate < BUY_LIMIT_RATE) {
  47. kLine.Rate = rate
  48. kLine.MaxRate = maxRate
  49. // kLine.Profit = NumKit.getSubFloat(rate > 0 ? rate - BUY_LIMIT_RATE : -BUY_LIMIT_RATE, 2)
  50. kLine.Profit = NumKit.getSubFloat(rate - BUY_LIMIT_RATE, 2)
  51. fakeDragonMap[symbol] = kLine
  52. if (!fakeCountMap[symbol]) {
  53. fakeCountMap[symbol] = kLine.Profit
  54. } else {
  55. fakeCountMap[symbol] += kLine.Profit
  56. }
  57. fakeCountMap[symbol] = NumKit.getSubFloat(fakeCountMap[symbol], 2)
  58. }
  59. }
  60. return fakeDragonMap
  61. }
  62. // 统计过去7日累计涨幅,跟这个无关
  63. function statisticA(kLines, index) {
  64. let startK = kLines[index - 7]
  65. let endK = kLines[index - 1]
  66. if (!startK || !endK) {
  67. return 0
  68. }
  69. return NumKit.getSubFloat(100 * (endK.Close - startK.Open) / startK.Open, 2)
  70. }
  71. // 过去30天的平均振幅,跟这个无关
  72. function statisticB(kLines, index) {
  73. let kCount = 0
  74. let totalRiseAndFall = 0
  75. for (let i = index - 1; i >= index - 30; i--) {
  76. let kLine = kLines[i]
  77. if (!kLines[i - 1]) break
  78. kCount += 1
  79. totalRiseAndFall += (100 * (kLine.High - kLine.Low) / kLine.Low)
  80. }
  81. if (kCount === 0) {
  82. return 0
  83. }
  84. return NumKit.getSubFloat(totalRiseAndFall / kCount, 2)
  85. }
  86. // 过去30天的平均(High - Close),跟这个可能有关系
  87. // TODO 将最近一个月的所有二维数据(y为盈利,x为平均(High - Close),进行二维化展开分析)
  88. function statisticC(kLines, index) {
  89. let kCount = 0
  90. let totalRiseAndFall = 0
  91. for (let i = index - 1; i >= index - 30; i--) {
  92. let kLine = kLines[i]
  93. if (!kLines[i - 1]) break
  94. kCount += 1
  95. totalRiseAndFall += (100 * (kLine.High - kLine.Close) / kLine.Close)
  96. }
  97. if (kCount === 0) {
  98. return 0
  99. }
  100. return NumKit.getSubFloat(totalRiseAndFall / kCount, 2)
  101. }
  102. function dragonAnalysis(kLinesMap, dragonMap, dayCount) {
  103. for (let symbol in dragonMap) {
  104. let kLines = kLinesMap[symbol]
  105. let index = kLines.length - (dayCount + 1)
  106. logger.info(
  107. `${symbol}的分析(${dragonMap[symbol].Profit}%)`
  108. // + `前7日累计涨幅${statisticA(kLines, index)}%。`
  109. // + `前30日平均振幅${statisticB(kLines, index)}%。`
  110. + `前30日平均(High - Close)${statisticC(kLines, index)}%。`
  111. )
  112. }
  113. }
  114. async function main() {
  115. let kLinesMap = await readData()
  116. const FIRST_FEW_DAYS = 1 // 第几天的数据,0表示今天,1表示昨天,2表示前天,以此类推
  117. const BUY_LIMIT_RATE = 2.5 // 从什么比例入场
  118. const BAKE_TEST_DAYS = 1 // 一共回测多少天
  119. let totalProfit = 0
  120. for (let day_count = FIRST_FEW_DAYS; day_count < FIRST_FEW_DAYS + BAKE_TEST_DAYS; day_count++) {
  121. // 赚钱榜
  122. let realDragonProfit = 0
  123. let realDragonMap = getRealDragonMap(kLinesMap, day_count, BUY_LIMIT_RATE)
  124. for (let symbol in realDragonMap) {
  125. realDragonProfit += realDragonMap[symbol].Profit
  126. // logger.info(realDragonMap[symbol].Symbol, realDragonMap[symbol].Profit, realDragonMap[symbol].Rate)
  127. }
  128. logger.info("----------------赚钱榜数据分析----------------")
  129. dragonAnalysis(kLinesMap, realDragonMap, day_count)
  130. // 亏钱榜
  131. let fakeDragonProfit = 0
  132. let fakeDragonMap = getFakeDragonMap(kLinesMap, day_count, BUY_LIMIT_RATE)
  133. for (let symbol in fakeDragonMap) {
  134. fakeDragonProfit += fakeDragonMap[symbol].Profit
  135. // logger.info(fakeDragonMap[symbol].Symbol, fakeDragonMap[symbol].Profit, fakeDragonMap[symbol].MaxRate, fakeDragonMap[symbol].Rate)
  136. }
  137. logger.info("----------------亏钱榜数据分析----------------")
  138. dragonAnalysis(kLinesMap, fakeDragonMap, day_count)
  139. realDragonProfit = NumKit.getSubFloat(realDragonProfit, 2)
  140. fakeDragonProfit = NumKit.getSubFloat(fakeDragonProfit, 2)
  141. let realLength = Object.keys(realDragonMap).length
  142. let fakeLength = Object.keys(fakeDragonMap).length
  143. let realRate = NumKit.getSubFloat(realLength / (realLength + fakeLength), 2)
  144. let fakeRate = NumKit.getSubFloat(1 - realRate, 2)
  145. let expRealProfit = NumKit.getSubFloat(realRate * realDragonProfit, 2)
  146. let expFakeProfit = NumKit.getSubFloat(fakeRate * fakeDragonProfit, 2)
  147. let synProfit = NumKit.getSubFloat(expFakeProfit + expRealProfit, 2)
  148. let avgProfit = NumKit.getSubFloat(synProfit / (realLength + fakeLength), 2)
  149. let index = kLinesMap['BTC_USDT'].length - (day_count + 1)
  150. let btcK = kLinesMap['BTC_USDT'][index]
  151. let dateStr = TimeKit.getDateByMillisecond(btcK.Time)
  152. let btcUpRate = NumKit.getSubFloat(100 * (btcK.Close - btcK.Open) / btcK.Open, 2)
  153. logger.info(`${day_count}日(${dateStr}, ${realLength + fakeLength}只),赚钱榜(${realLength}只)利润${realDragonProfit}%`
  154. + `,亏钱榜(${fakeLength}只)利润${fakeDragonProfit}%`
  155. + `,赚钱榜期望利润${expRealProfit}%,亏钱榜期望利润${expFakeProfit}%,综合利润${synProfit}%,平均每只利润${avgProfit}%,BTC涨幅${btcUpRate}%`
  156. )
  157. totalProfit += avgProfit
  158. totalProfit = NumKit.getSubFloat(totalProfit, 2)
  159. }
  160. // let dayProfit = NumKit.getSubFloat(totalProfit / BAKE_TEST_DAYS, 2)
  161. // logger.info(`利润期望值总和:${totalProfit}%,平均日化${dayProfit}%。`)
  162. // for (let symbol in fakeCountMap) {
  163. // let kLines = kLinesMap[symbol]
  164. // let startIndex = kLines.length - BAKE_TEST_DAYS
  165. // let endIndex = kLines.length - 1
  166. //
  167. // logger.info(`${symbol} 盈${realCountMap[symbol]},亏${fakeCountMap[symbol]},大于5%涨幅的共有${statisticA(kLines, startIndex, endIndex)}日。`)
  168. // }
  169. }
  170. main().catch((error) => {
  171. logger.error(error.stack);
  172. process.exitCode = 1;
  173. })