十面埋伏分析.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. const logger = require("./utils/logger");
  2. const NumKit = require('./utils/num-kit')
  3. const TimeKit = require('./utils/time-kit')
  4. const ChartKit = require('./utils/chart-kit');
  5. const fs = require('fs').promises;
  6. async function readData() {
  7. let data = await fs.readFile('./data/k_lines.json', 'utf8')
  8. return JSON.parse(data)
  9. }
  10. // 统计过去N日累计涨幅,【在-1%~-20%容易有亏损,有一定关系】
  11. function statisticA(kLines, index) {
  12. let startK = kLines[index - 10]
  13. let endK = kLines[index - 1]
  14. if (!startK || !endK) {
  15. return 0
  16. }
  17. return parseInt(100 * (endK.Close - startK.Open) / startK.Open) + 100
  18. }
  19. // 返回过去一共N天涨幅超过M%【这个有关的】
  20. function statisticB(kLines, index) {
  21. let count = 0
  22. for (let i = index - 1; i >= index - 3; i--) {
  23. let kLine = kLines[i]
  24. if (!kLines[i - 1]) break
  25. if (100 * (kLine.Close - kLine.Open) / kLine.Open < 3) continue
  26. count += 1
  27. }
  28. return count
  29. }
  30. // 指标过滤
  31. function filter(kLines, index) {
  32. // 一共N天涨幅超过M%
  33. if (statisticB(kLines, index) !== 0) return false
  34. // 过去N日累计涨幅,85表示亏15%,115表示赚15%,100是分界线
  35. let upRateN = statisticA(kLines, index)
  36. if (upRateN >= 85 && upRateN <= 100) return false
  37. return true
  38. }
  39. let realCountMap = {}
  40. function getRealDragonMap(kLinesMap, dayCount, BUY_LIMIT_RATE) {
  41. let realDragonMap = {}
  42. for (let symbol in kLinesMap) {
  43. let kLines = kLinesMap[symbol]
  44. let index = kLines.length - (dayCount + 1)
  45. let kLine = kLines[index]
  46. let prevKline = kLines[index - 1]
  47. // 开盘第一天不计算
  48. if (!kLine || !prevKline) continue
  49. // 指标过滤
  50. if (!filter(kLines, index)) continue
  51. let rate = 100 * (kLine.Close - kLine.Open) / kLine.Open
  52. if (rate > BUY_LIMIT_RATE) {
  53. kLine.Rate = rate
  54. kLine.Profit = NumKit.getSubFloat(rate - BUY_LIMIT_RATE, 2)
  55. realDragonMap[symbol] = kLine
  56. if (!realCountMap[symbol]) {
  57. realCountMap[symbol] = kLine.Profit
  58. } else {
  59. realCountMap[symbol] += kLine.Profit
  60. }
  61. realCountMap[symbol] = NumKit.getSubFloat(realCountMap[symbol], 2)
  62. }
  63. }
  64. return realDragonMap
  65. }
  66. let fakeCountMap = {}
  67. function getFakeDragonMap(kLinesMap, dayCount, BUY_LIMIT_RATE) {
  68. let fakeDragonMap = {}
  69. for (let symbol in kLinesMap) {
  70. let kLines = kLinesMap[symbol]
  71. let index = kLines.length - (dayCount + 1)
  72. let kLine = kLines[index]
  73. let prevKline = kLines[index - 1]
  74. // 开盘第一天不计算
  75. if (!kLine || (!prevKline)) continue
  76. // 指标过滤
  77. if (!filter(kLines, index)) continue
  78. let rate = 100 * (kLine.Close - kLine.Open) / kLine.Open
  79. if (rate < BUY_LIMIT_RATE) {
  80. kLine.Rate = rate
  81. // kLine.Profit = NumKit.getSubFloat(rate > 0 ? rate - BUY_LIMIT_RATE : -BUY_LIMIT_RATE, 2)
  82. kLine.Profit = NumKit.getSubFloat(rate - BUY_LIMIT_RATE, 2)
  83. fakeDragonMap[symbol] = kLine
  84. if (!fakeCountMap[symbol]) {
  85. fakeCountMap[symbol] = kLine.Profit
  86. } else {
  87. fakeCountMap[symbol] += kLine.Profit
  88. }
  89. fakeCountMap[symbol] = NumKit.getSubFloat(fakeCountMap[symbol], 2)
  90. }
  91. }
  92. return fakeDragonMap
  93. }
  94. let dataLeft = []
  95. let dataRight = []
  96. let tempLeft = []
  97. let tempRight = []
  98. let dataY = [...Array(100).keys()]
  99. function dragonAnalysis(btcKLines, kLinesMap, dragonMap, dayCount) {
  100. for (let symbol in dragonMap) {
  101. let kLines = kLinesMap[symbol]
  102. let index = kLines.length - (dayCount + 1)
  103. let x = statisticA(kLines, index)
  104. let y = dragonMap[symbol].Profit
  105. // logger.info(
  106. // `${symbol}的分析(${y}%)`
  107. // // + `前7日累计涨幅${statisticA(kLines, index)}%。`
  108. // // + `前30日平均振幅${statisticB(kLines, index)}%。`
  109. // + `前30日平均(High - Close)${x}%。`
  110. // )
  111. // 打印实际的量
  112. // if (y > 0) {
  113. // if (dataRight[x]) {
  114. // dataRight[x] += y
  115. // } else {
  116. // dataRight[x] = y
  117. // }
  118. // } else {
  119. // if (dataLeft[x]) {
  120. // dataLeft[x] += y
  121. // } else {
  122. // dataLeft[x] = y
  123. // }
  124. // }
  125. // 打印倍数
  126. if (y > 0) {
  127. if (tempRight[x]) {
  128. tempRight[x] += y
  129. } else {
  130. tempRight[x] = y
  131. }
  132. } else {
  133. if (tempLeft[x]) {
  134. tempLeft[x] += y
  135. } else {
  136. tempLeft[x] = y
  137. }
  138. }
  139. dataRight[x] = (tempLeft[x]?tempRight[x]/Math.abs(tempLeft[x]):0)
  140. if (dataRight[x] > 10) dataRight[x] = 10
  141. if (dataRight[x] < 0.5) dataRight[x] = 0.5
  142. }
  143. }
  144. async function main() {
  145. let kLinesMap = await readData()
  146. const FIRST_FEW_DAYS = 180 // 第几天的数据,0表示今天,1表示昨天,2表示前天,以此类推
  147. const BUY_LIMIT_RATE = 0 // 从什么比例入场
  148. const BAKE_TEST_DAYS = 30 // 一共回测多少天, 150天是熊市最没有交易量的时候
  149. let btcKLines = kLinesMap['BTC_USDT']
  150. let totalProfit = 0
  151. for (let day_count = FIRST_FEW_DAYS; day_count < FIRST_FEW_DAYS + BAKE_TEST_DAYS; day_count++) {
  152. // 赚钱榜
  153. // logger.info("----------------赚钱榜数据分析----------------")
  154. let realDragonProfit = 0
  155. let realDragonMap = getRealDragonMap(kLinesMap, day_count, BUY_LIMIT_RATE)
  156. for (let symbol in realDragonMap) {
  157. realDragonProfit += realDragonMap[symbol].Profit
  158. // logger.info(`${realDragonMap[symbol].Symbol}, ${realDragonMap[symbol].Profit}%`)
  159. }
  160. dragonAnalysis(btcKLines, kLinesMap, realDragonMap, day_count)
  161. // logger.info("----------------亏钱榜数据分析----------------")
  162. // 亏钱榜
  163. let fakeDragonProfit = 0
  164. let fakeDragonMap = getFakeDragonMap(kLinesMap, day_count, BUY_LIMIT_RATE)
  165. for (let symbol in fakeDragonMap) {
  166. fakeDragonProfit += fakeDragonMap[symbol].Profit
  167. // logger.info(`${fakeDragonMap[symbol].Symbol}, ${fakeDragonMap[symbol].Profit}%`)
  168. }
  169. dragonAnalysis(btcKLines, kLinesMap, fakeDragonMap, day_count)
  170. realDragonProfit = NumKit.getSubFloat(realDragonProfit, 2)
  171. fakeDragonProfit = NumKit.getSubFloat(fakeDragonProfit, 2)
  172. let realLength = Object.keys(realDragonMap).length
  173. let fakeLength = Object.keys(fakeDragonMap).length
  174. let realRate = NumKit.getSubFloat(realLength / (realLength + fakeLength), 2)
  175. let fakeRate = NumKit.getSubFloat(1 - realRate, 2)
  176. let expRealProfit = NumKit.getSubFloat(realRate * realDragonProfit, 2)
  177. let expFakeProfit = NumKit.getSubFloat(fakeRate * fakeDragonProfit, 2)
  178. let synProfit = NumKit.getSubFloat(expFakeProfit + expRealProfit, 2)
  179. let avgProfit = NumKit.getSubFloat(synProfit / (realLength + fakeLength), 2)
  180. let index = kLinesMap['BTC_USDT'].length - (day_count + 1)
  181. let btcK = kLinesMap['BTC_USDT'][index]
  182. let dateStr = TimeKit.getDateByMillisecond(btcK.Time)
  183. let btcUpRate = NumKit.getSubFloat(100 * (btcK.Close - btcK.Open) / btcK.Open, 2)
  184. logger.info(`${day_count}日(${dateStr}, ${realLength + fakeLength}只),赚钱榜(${realLength}只)利润${realDragonProfit}%`
  185. + `,亏钱榜(${fakeLength}只)利润${fakeDragonProfit}%`
  186. + `,赚钱榜期望利润${expRealProfit}%,亏钱榜期望利润${expFakeProfit}%,综合利润${synProfit}%,平均每只利润${avgProfit}%,BTC涨幅${btcUpRate}%`
  187. )
  188. totalProfit += avgProfit
  189. totalProfit = NumKit.getSubFloat(totalProfit, 2)
  190. }
  191. let dayProfit = NumKit.getSubFloat(totalProfit / BAKE_TEST_DAYS, 2)
  192. logger.info(`利润期望值总和:${totalProfit}%,平均日化${dayProfit}%。`)
  193. // let lastData = []
  194. // for (let x = 0; x < dataRight.length; x++) {
  195. // lastData.push([x, dataRight[x]])
  196. // }
  197. let rst = 'option=' + JSON.stringify(ChartKit.printBar(dataY, dataLeft, dataRight), null, 2)
  198. // let rst = 'option=' + JSON.stringify(ChartKit.printPointChart(lastData), null, 2)
  199. require('fs').writeFile('./data/option.txt', rst, 'utf8', (err) => {
  200. if (err) {
  201. logger.error('写入文件时发生错误:', err);
  202. } else {
  203. logger.info('分析结果已写入到 ./data/option.txt');
  204. }
  205. });
  206. }
  207. main().catch((error) => {
  208. logger.error(error.stack);
  209. process.exitCode = 1;
  210. })