w-trade-backtest 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/.editorconfig +9 -0
  2. package/.eslintignore +3 -0
  3. package/.eslintrc.js +55 -0
  4. package/.jsdoc +25 -0
  5. package/README.md +167 -0
  6. package/SECURITY.md +5 -0
  7. package/babel.config.js +16 -0
  8. package/dist/renderOrdersTable.js +217 -0
  9. package/dist/renderOrdersTimeline.js +159 -0
  10. package/dist/renderProfitPlot.js +198 -0
  11. package/dist/renderSummary.js +194 -0
  12. package/dist/tmp.html +232 -0
  13. package/dist/w-trade-backtest.umd.js +32 -0
  14. package/dist/w-trade-backtest.umd.js.map +1 -0
  15. package/docs/calcOrders.mjs.html +278 -0
  16. package/docs/calcOrdersRatio.mjs.html +146 -0
  17. package/docs/calcOrdersSummary.mjs.html +506 -0
  18. package/docs/calcOrdersSummarySimple.mjs.html +207 -0
  19. package/docs/calcSummary.mjs.html +201 -0
  20. package/docs/closeAndSummaryOrders.mjs.html +265 -0
  21. package/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  22. package/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  23. package/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  24. package/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  25. package/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  26. package/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  27. package/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  28. package/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  29. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  30. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
  31. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  32. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  33. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  34. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  35. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
  36. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  37. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  38. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  39. package/docs/genReport.mjs.html +196 -0
  40. package/docs/genReportCore.mjs.html +128 -0
  41. package/docs/global.html +4231 -0
  42. package/docs/index.html +84 -0
  43. package/docs/runStrategies.mjs.html +244 -0
  44. package/docs/runStrategy.mjs.html +455 -0
  45. package/docs/scripts/collapse.js +39 -0
  46. package/docs/scripts/commonNav.js +28 -0
  47. package/docs/scripts/linenumber.js +25 -0
  48. package/docs/scripts/nav.js +12 -0
  49. package/docs/scripts/polyfill.js +4 -0
  50. package/docs/scripts/prettify/Apache-License-2.0.txt +202 -0
  51. package/docs/scripts/prettify/lang-css.js +2 -0
  52. package/docs/scripts/prettify/prettify.js +28 -0
  53. package/docs/scripts/search.js +99 -0
  54. package/docs/styles/jsdoc.css +776 -0
  55. package/docs/styles/prettify.css +80 -0
  56. package/g.mjs +146 -0
  57. package/package.json +30 -0
  58. package/script.txt +19 -0
  59. package/src/WTradeBacktest.mjs +27 -0
  60. package/src/calcOrders.mjs +206 -0
  61. package/src/calcOrdersRatio.mjs +74 -0
  62. package/src/calcOrdersSummary.mjs +434 -0
  63. package/src/calcOrdersSummarySimple.mjs +135 -0
  64. package/src/calcSummary.mjs +129 -0
  65. package/src/closeAndSummaryOrders.mjs +193 -0
  66. package/src/genReport.mjs +124 -0
  67. package/src/genReportCore.mjs +56 -0
  68. package/src/ott.mjs +28 -0
  69. package/src/readJson.mjs +26 -0
  70. package/src/renderOrdersTable.js +217 -0
  71. package/src/renderOrdersTimeline.js +159 -0
  72. package/src/renderProfitPlot.js +198 -0
  73. package/src/renderSummary.js +194 -0
  74. package/src/runStrategies.mjs +172 -0
  75. package/src/runStrategy.mjs +383 -0
  76. package/src/tmp.html +232 -0
  77. package/src/writeJson.mjs +31 -0
  78. package/src/writeTxt.mjs +19 -0
  79. package/test/unit-WTradeBacktest.test.mjs +541 -0
  80. package/toolg/addVersion.mjs +4 -0
  81. package/toolg/cleanFolder.mjs +5 -0
  82. package/toolg/gDistRollup.mjs +51 -0
  83. package/toolg/gDocsExams.mjs +48 -0
  84. package/toolg/modifyReadme.mjs +4 -0
@@ -0,0 +1,84 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+
5
+ <meta charset="utf-8">
6
+ <title>Home - Documentation</title>
7
+
8
+
9
+ <script src="scripts/prettify/prettify.js"></script>
10
+ <script src="scripts/prettify/lang-css.js"></script>
11
+ <!--[if lt IE 9]>
12
+ <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
13
+ <![endif]-->
14
+ <link type="text/css" rel="stylesheet" href="styles/prettify.css">
15
+ <link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
16
+ <script src="scripts/nav.js" defer></script>
17
+
18
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
19
+ </head>
20
+ <body>
21
+
22
+ <input type="checkbox" id="nav-trigger" class="nav-trigger" />
23
+ <label for="nav-trigger" class="navicon-button x">
24
+ <div class="navicon"></div>
25
+ </label>
26
+
27
+ <label for="nav-trigger" class="overlay"></label>
28
+
29
+ <nav >
30
+
31
+
32
+ <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#calcOrders">calcOrders</a></li><li><a href="global.html#calcOrdersRatio">calcOrdersRatio</a></li><li><a href="global.html#calcOrdersSummary">calcOrdersSummary</a></li><li><a href="global.html#calcOrdersSummarySimple">calcOrdersSummarySimple</a></li><li><a href="global.html#calcSummary">calcSummary</a></li><li><a href="global.html#closeAndSummaryOrders">closeAndSummaryOrders</a></li><li><a href="global.html#genReport">genReport</a></li><li><a href="global.html#genReportCore">genReportCore</a></li><li><a href="global.html#runStrategies">runStrategies</a></li><li><a href="global.html#runStrategy">runStrategy</a></li></ul>
33
+
34
+ </nav>
35
+
36
+ <div id="main">
37
+
38
+
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+ <section class="package">
47
+ <h3> </h3>
48
+ </section>
49
+
50
+
51
+
52
+
53
+
54
+
55
+
56
+
57
+
58
+
59
+
60
+
61
+
62
+
63
+
64
+
65
+
66
+
67
+
68
+
69
+ </div>
70
+
71
+ <br class="clear">
72
+
73
+ <footer>
74
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Sun Aug 02 2026 20:09:43 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
75
+ </footer>
76
+
77
+ <script>prettyPrint();</script>
78
+ <script src="scripts/polyfill.js"></script>
79
+ <script src="scripts/linenumber.js"></script>
80
+
81
+
82
+
83
+ </body>
84
+ </html>
@@ -0,0 +1,244 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+
5
+ <meta charset="utf-8">
6
+ <title>runStrategies.mjs - Documentation</title>
7
+
8
+
9
+ <script src="scripts/prettify/prettify.js"></script>
10
+ <script src="scripts/prettify/lang-css.js"></script>
11
+ <!--[if lt IE 9]>
12
+ <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
13
+ <![endif]-->
14
+ <link type="text/css" rel="stylesheet" href="styles/prettify.css">
15
+ <link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
16
+ <script src="scripts/nav.js" defer></script>
17
+
18
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
19
+ </head>
20
+ <body>
21
+
22
+ <input type="checkbox" id="nav-trigger" class="nav-trigger" />
23
+ <label for="nav-trigger" class="navicon-button x">
24
+ <div class="navicon"></div>
25
+ </label>
26
+
27
+ <label for="nav-trigger" class="overlay"></label>
28
+
29
+ <nav >
30
+
31
+
32
+ <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#calcOrders">calcOrders</a></li><li><a href="global.html#calcOrdersRatio">calcOrdersRatio</a></li><li><a href="global.html#calcOrdersSummary">calcOrdersSummary</a></li><li><a href="global.html#calcOrdersSummarySimple">calcOrdersSummarySimple</a></li><li><a href="global.html#calcSummary">calcSummary</a></li><li><a href="global.html#closeAndSummaryOrders">closeAndSummaryOrders</a></li><li><a href="global.html#genReport">genReport</a></li><li><a href="global.html#genReportCore">genReportCore</a></li><li><a href="global.html#runStrategies">runStrategies</a></li><li><a href="global.html#runStrategy">runStrategy</a></li></ul>
33
+
34
+ </nav>
35
+
36
+ <div id="main">
37
+
38
+ <h1 class="page-title">runStrategies.mjs</h1>
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+ <section>
47
+ <article>
48
+ <pre class="prettyprint source linenums"><code>import flatten from 'lodash-es/flatten.js'
49
+ import get from 'lodash-es/get.js'
50
+ import isNumber from 'lodash-es/isNumber.js'
51
+ import map from 'lodash-es/map.js'
52
+ import size from 'lodash-es/size.js'
53
+ import sortBy from 'lodash-es/sortBy.js'
54
+ import isestr from 'wsemi/src/isestr.mjs'
55
+ import pmSeries from 'wsemi/src/pmSeries.mjs'
56
+ import runStrategy from './runStrategy.mjs'
57
+ import calcSummary from './calcSummary.mjs'
58
+
59
+
60
+ /**
61
+ * 執行多策略回測
62
+ *
63
+ * 逐策略呼叫runStrategy(withSummary:false),各單附加策略sid後合併並依timeStart排序
64
+ * 以各策略settings.uIni總和為初始資金呼叫calcSummary統計合併摘要
65
+ * 個別策略執行失敗(如時間點無參數無法下單)時強制略過
66
+ *
67
+ * Unit Test: {@link https://github.com/yuda-lyu/w-trade-backtest/blob/master/test/unit-WTradeBacktest.test.mjs Github}
68
+ * @function
69
+ * @param {Function} ott 輸入時區時間函數,傳入時間字串回傳dayjs時間物件(可用src/ott.mjs或自行以dayjs包裝)
70
+ * @param {Array} strategies 輸入策略陣列,各元素需含sid與runStrategy之strategy欄位
71
+ * @param {Function} funGetSeries 輸入序列查詢async函數,依key回傳時間序列陣列
72
+ * @param {Object} [opt={}] 輸入設定物件,預設{}
73
+ * @param {Boolean} [opt.withCalcOrderProfitOrLoss=true] 輸入是否經calcOrders結算訂單布林值,預設true
74
+ * @param {Boolean} [opt.withSummary=true] 輸入是否計算統計摘要布林值,預設true
75
+ * @returns {Promise} 回傳Promise,resolve為{orders,summary}物件
76
+ * @example
77
+ *
78
+ * let arrOhlc = [
79
+ * { time: '2020-01-01T00:00:00', Open: 100, High: 101, Low: 99, Close: 100 },
80
+ * { time: '2020-01-01T04:00:00', Open: 100, High: 106, Low: 100, Close: 105 },
81
+ * { time: '2020-01-01T08:00:00', Open: 105, High: 107, Low: 102, Close: 103 },
82
+ * { time: '2020-01-01T12:00:00', Open: 103, High: 104, Low: 94, Close: 95 },
83
+ * { time: '2020-01-01T16:00:00', Open: 95, High: 98, Low: 92, Close: 93 },
84
+ * { time: '2020-01-01T20:00:00', Open: 93, High: 99, Low: 95, Close: 97 },
85
+ * ]
86
+ *
87
+ * let arrSig = [
88
+ * { time: '2020-01-01T00:00:00', param: 1 },
89
+ * { time: '2020-01-01T04:00:00', param: 0 },
90
+ * { time: '2020-01-01T08:00:00', param: 1 },
91
+ * { time: '2020-01-01T12:00:00', param: 0 },
92
+ * { time: '2020-01-01T16:00:00', param: 0 },
93
+ * { time: '2020-01-01T20:00:00', param: 0 },
94
+ * ]
95
+ *
96
+ * let funGetSeries = async (key) => {
97
+ * if (key === 'btc') {
98
+ * return arrOhlc
99
+ * }
100
+ * if (key === 'sig') {
101
+ * return arrSig
102
+ * }
103
+ * throw new Error(`invalid key[${key}]`)
104
+ * }
105
+ *
106
+ * let settings = { uIni: 1000, uTrade: 100, rTakeProfit: 0.05, rStopLoss: 0.03, rFee: 0.0005 }
107
+ * let strategies = [
108
+ * { sid: 's1', mode: 'long', keyOhlc: 'btc', conds: [{ key: 'sig', sym: '>', th: 0.5, opr: 'and' }], settings },
109
+ * { sid: 's2', mode: 'short', keyOhlc: 'btc', conds: [{ key: 'sig', sym: '&lt;', th: 0.5, opr: 'and' }], settings },
110
+ * ]
111
+ *
112
+ * let rr = await runStrategies(ott, strategies, funGetSeries)
113
+ * console.log(rr.orders.map((o) => `${o.sid} ${o.timeStart} ${o.mode} ${o.modeResult || 'unsettled'}`))
114
+ * // => [
115
+ * // 's1 2020-01-01T00:00:00 long profit',
116
+ * // 's2 2020-01-01T04:00:00 short profit',
117
+ * // 's1 2020-01-01T08:00:00 long loss',
118
+ * // 's2 2020-01-01T12:00:00 short loss',
119
+ * // 's2 2020-01-01T16:00:00 short loss',
120
+ * // 's2 2020-01-01T20:00:00 short unsettled'
121
+ * // ]
122
+ * console.log(rr.summary.uIni, rr.summary.numTrade, rr.summary.rWin)
123
+ * // => 2000 6 40.00%
124
+ *
125
+ */
126
+ let runStrategies = async (ott, strategies, funGetSeries, opt = {}) => {
127
+
128
+ //withCalcOrderProfitOrLoss
129
+ let withCalcOrderProfitOrLoss = get(opt, 'withCalcOrderProfitOrLoss', true)
130
+
131
+ //withSummary
132
+ let withSummary = get(opt, 'withSummary', true)
133
+
134
+ //uIniAll, ordersAll
135
+ let uIniAll = 0
136
+ let ordersAll = []
137
+ let r = null
138
+ await pmSeries(strategies, async(strategy, k) => {
139
+
140
+ //有些策略因為時間點無參數故無法計算, 代表無法下單, 故強制略過
141
+ try {
142
+
143
+ //runStrategy
144
+ r = await runStrategy(ott, strategy, funGetSeries, { withCalcOrderProfitOrLoss, withSummary: false })
145
+
146
+ //uIni
147
+ let uIni = get(strategy, 'settings.uIni', '')
148
+ if (!isNumber(uIni)) {
149
+ throw new Error(`uIni[${uIni}] is not a number`)
150
+ }
151
+ // console.log(' ', 'uIni =', uIni, 'numTrade =', strategy.summary.numTrade)
152
+
153
+ //累加初始金額(本金)
154
+ uIniAll += uIni
155
+
156
+ //add sid, push
157
+ if (size(r.orders) >= 1) {
158
+
159
+ //各單額外儲存策略sid
160
+ r.orders = map(r.orders, (o) => {
161
+ o.sid = strategy.sid
162
+ return o
163
+ })
164
+
165
+ //push
166
+ ordersAll.push(r.orders)
167
+
168
+ }
169
+
170
+ }
171
+ catch (err) {
172
+ // console.log(err)
173
+ }
174
+
175
+ })
176
+ ordersAll = flatten(ordersAll)
177
+ // console.log('ordersAll', ordersAll)
178
+
179
+ //sortBy
180
+ if (size(ordersAll) >= 2) {
181
+ ordersAll = sortBy(ordersAll, 'timeStart')
182
+ }
183
+ // console.log('size(ordersAll)', size(ordersAll))
184
+
185
+ //timeOhlcStart, timeOhlcEnd
186
+ let timeOhlcStart = get(r, 'summary.timeOhlcStart', '') //各策略ohlc起訖時間皆相同, 取最後r內的timeOhlcStart來使用
187
+ let timeOhlcEnd = get(r, 'summary.timeOhlcEnd', '') //各策略ohlc起訖時間皆相同, 取最後r內的timeOhlcEnd來使用
188
+
189
+ //check
190
+ if (!isestr(timeOhlcStart)) {
191
+ throw new Error(`invalid timeOhlcStart`)
192
+ }
193
+ if (!isestr(timeOhlcEnd)) {
194
+ throw new Error(`invalid timeOhlcEnd`)
195
+ }
196
+
197
+ //summary
198
+ let summary = {
199
+ timeTest: ott().format('YYYY-MM-DDTHH:mm:ssZ'),
200
+ timeOhlcStart,
201
+ timeOhlcEnd,
202
+ }
203
+
204
+ //withSummary
205
+ if (withSummary) {
206
+ summary = await calcSummary(ott, uIniAll, ordersAll, timeOhlcStart, timeOhlcEnd)
207
+ }
208
+
209
+ //rr
210
+ let rr = {
211
+ orders: ordersAll,
212
+ summary,
213
+ }
214
+
215
+ return rr
216
+ }
217
+
218
+ export default runStrategies
219
+
220
+ </code></pre>
221
+ </article>
222
+ </section>
223
+
224
+
225
+
226
+
227
+
228
+
229
+ </div>
230
+
231
+ <br class="clear">
232
+
233
+ <footer>
234
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Sun Aug 02 2026 20:09:43 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
235
+ </footer>
236
+
237
+ <script>prettyPrint();</script>
238
+ <script src="scripts/polyfill.js"></script>
239
+ <script src="scripts/linenumber.js"></script>
240
+
241
+
242
+
243
+ </body>
244
+ </html>