w-trade-solve 1.0.1

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 (88) 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 +132 -0
  6. package/SECURITY.md +5 -0
  7. package/babel.config.js +16 -0
  8. package/dist/w-trade-solve.umd.js +19 -0
  9. package/dist/w-trade-solve.umd.js.map +1 -0
  10. package/docs/calcFitness.mjs.html +205 -0
  11. package/docs/calcLevelNumTrade.mjs.html +164 -0
  12. package/docs/cont.mjs.html +94 -0
  13. package/docs/estimComps.mjs.html +190 -0
  14. package/docs/estimFinder.mjs.html +197 -0
  15. package/docs/estimKeys.mjs.html +571 -0
  16. package/docs/estimPicks.mjs.html +200 -0
  17. package/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  18. package/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  19. package/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  20. package/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  21. package/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  22. package/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  23. package/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  24. package/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  25. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  26. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
  27. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  28. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  29. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  30. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  31. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
  32. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  33. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  34. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  35. package/docs/genSid.mjs.html +125 -0
  36. package/docs/genStrategyFileName.mjs.html +131 -0
  37. package/docs/genTid.mjs.html +113 -0
  38. package/docs/global.html +4932 -0
  39. package/docs/index.html +84 -0
  40. package/docs/ott.mjs.html +137 -0
  41. package/docs/p2r.mjs.html +111 -0
  42. package/docs/readStrategies.mjs.html +203 -0
  43. package/docs/scripts/collapse.js +39 -0
  44. package/docs/scripts/commonNav.js +28 -0
  45. package/docs/scripts/linenumber.js +25 -0
  46. package/docs/scripts/nav.js +12 -0
  47. package/docs/scripts/polyfill.js +4 -0
  48. package/docs/scripts/prettify/Apache-License-2.0.txt +202 -0
  49. package/docs/scripts/prettify/lang-css.js +2 -0
  50. package/docs/scripts/prettify/prettify.js +28 -0
  51. package/docs/scripts/search.js +99 -0
  52. package/docs/styles/jsdoc.css +776 -0
  53. package/docs/styles/prettify.css +80 -0
  54. package/g.mjs +110 -0
  55. package/package.json +31 -0
  56. package/script.txt +19 -0
  57. package/src/WTradeSolve.mjs +29 -0
  58. package/src/calcFitness.mjs +133 -0
  59. package/src/calcLevelNumTrade.mjs +92 -0
  60. package/src/cont.mjs +22 -0
  61. package/src/estimComps.mjs +118 -0
  62. package/src/estimFinder.mjs +125 -0
  63. package/src/estimKeys.mjs +499 -0
  64. package/src/estimPicks.mjs +128 -0
  65. package/src/genSid.mjs +53 -0
  66. package/src/genStrategyFileName.mjs +59 -0
  67. package/src/genTid.mjs +41 -0
  68. package/src/ott.mjs +65 -0
  69. package/src/p2r.mjs +39 -0
  70. package/src/readStrategies.mjs +131 -0
  71. package/test/unit-WTradeSolve.test.mjs +83 -0
  72. package/test/unit-calcFitness.test.mjs +121 -0
  73. package/test/unit-calcLevelNumTrade.test.mjs +80 -0
  74. package/test/unit-estimComps.test.mjs +193 -0
  75. package/test/unit-estimFinder.test.mjs +184 -0
  76. package/test/unit-estimKeys.test.mjs +260 -0
  77. package/test/unit-estimPicks.test.mjs +241 -0
  78. package/test/unit-genSid.test.mjs +75 -0
  79. package/test/unit-genStrategyFileName.test.mjs +85 -0
  80. package/test/unit-genTid.test.mjs +72 -0
  81. package/test/unit-p2r.test.mjs +51 -0
  82. package/test/unit-readStrategies.test.mjs +258 -0
  83. package/test/unit-setup.mjs +119 -0
  84. package/toolg/addVersion.mjs +4 -0
  85. package/toolg/cleanFolder.mjs +5 -0
  86. package/toolg/gDistRollup.mjs +37 -0
  87. package/toolg/gDocsExams.mjs +48 -0
  88. package/toolg/modifyReadme.mjs +4 -0
@@ -0,0 +1,205 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+
5
+ <meta charset="utf-8">
6
+ <title>calcFitness.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#calcFitness">calcFitness</a></li><li><a href="global.html#calcLevelNumTrade">calcLevelNumTrade</a></li><li><a href="global.html#cont">cont</a></li><li><a href="global.html#estimComps">estimComps</a></li><li><a href="global.html#estimFinder">estimFinder</a></li><li><a href="global.html#estimKeys">estimKeys</a></li><li><a href="global.html#estimPicks">estimPicks</a></li><li><a href="global.html#genSid">genSid</a></li><li><a href="global.html#genStrategyFileName">genStrategyFileName</a></li><li><a href="global.html#genTid">genTid</a></li><li><a href="global.html#nowTpeStr">nowTpeStr</a></li><li><a href="global.html#nowTpeStrp">nowTpeStrp</a></li><li><a href="global.html#ott">ott</a></li><li><a href="global.html#p2r">p2r</a></li><li><a href="global.html#readStrategies">readStrategies</a></li></ul>
33
+
34
+ </nav>
35
+
36
+ <div id="main">
37
+
38
+ <h1 class="page-title">calcFitness.mjs</h1>
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+ <section>
47
+ <article>
48
+ <pre class="prettyprint source linenums"><code>import cint from 'wsemi/src/cint.mjs'
49
+ import p2r from './p2r.mjs'
50
+
51
+
52
+ /**
53
+ * 計算策略適應值fitness
54
+ *
55
+ * 供最佳化求解使用之目標函數值,數值越小代表策略越佳
56
+ * 由勝率與最終等效年化盈虧兩者組成: 勝率rWin限縮至[0,1],等效年化盈虧rEquivalentCumuProfitOrLossFinalNormYear限縮至[0,0.5]再正規化至[0,1],兩者皆轉為越小越好後,以權重2與1加權求和,故無懲罰時fitness落於[0,3]
57
+ * 交易次數為0時加上懲罰值1000000,最終累計盈虧金額(summary.uEquityFinal-settings.uIni)小於等於0時再加上懲罰值1000000,故兩者皆觸發時可達2000000以上
58
+ *
59
+ * Unit Test: {@link https://github.com/yuda-lyu/w-trade-solve/blob/master/test/unit-calcFitness.test.mjs Github}
60
+ * @function
61
+ * @param {Object} settings 輸入策略設定物件,需含uIni(初始資金)欄位
62
+ * @param {Object} summary 輸入回測統計摘要物件,需含numTrade(交易次數)、uEquityFinal(最終權益金額)、rWin(勝率百分比字串)、rEquivalentCumuProfitOrLossFinalNormYear(最終等效年化盈虧百分比字串)欄位
63
+ * @returns {Number} 回傳適應值數值,越小代表策略越佳
64
+ * @example
65
+ *
66
+ * let settings = { uIni: 1000 }
67
+ *
68
+ * //勝率60%, 等效年化盈虧25%(正規化後0.5), fitness = 2*(1-0.6) + 1*(1-0.5) = 1.3
69
+ * let summary = {
70
+ * numTrade: 30,
71
+ * uEquityFinal: 1200,
72
+ * rWin: '60%',
73
+ * rEquivalentCumuProfitOrLossFinalNormYear: '25%',
74
+ * }
75
+ * console.log(calcFitness(settings, summary))
76
+ * // => 1.3
77
+ *
78
+ * //無交易且無獲利時, 兩懲罰值皆觸發
79
+ * let summaryNone = {
80
+ * numTrade: 0,
81
+ * uEquityFinal: 1000,
82
+ * rWin: '',
83
+ * rEquivalentCumuProfitOrLossFinalNormYear: '',
84
+ * }
85
+ * console.log(calcFitness(settings, summaryNone))
86
+ * // => 2000003
87
+ *
88
+ */
89
+ let calcFitness = (settings, summary) => {
90
+
91
+ //numTrade
92
+ let numTrade = cint(summary.numTrade)
93
+
94
+ //uIni
95
+ let uIni = settings.uIni
96
+
97
+ // //uTradeAllMax
98
+ // let uTradeAllMax = summary.uTradeAllMax
99
+ // // console.log('uTradeAllMax', uTradeAllMax)
100
+
101
+ // //uDrawdownMax
102
+ // let uDrawdownMax = summary.uDrawdownMax
103
+
104
+ //uEquityFinal
105
+ let uEquityFinal = summary.uEquityFinal
106
+
107
+ //uCumuProfitOrLossFinal
108
+ let uCumuProfitOrLossFinal = uEquityFinal - uIni
109
+ // console.log('uCumuProfitOrLossFinal', uCumuProfitOrLossFinal)
110
+
111
+ //rEquivalentCumuProfitOrLossFinalNormYear, 等效年化報酬率
112
+ let rEquivalentCumuProfitOrLossFinalNormYear = p2r(summary.rEquivalentCumuProfitOrLossFinalNormYear)
113
+ rEquivalentCumuProfitOrLossFinalNormYear = Math.min(Math.max(rEquivalentCumuProfitOrLossFinalNormYear, 0), 0.5) //最大限制為年化50% (依實際年化分布調整)
114
+ rEquivalentCumuProfitOrLossFinalNormYear /= 0.5 //正規化最大值1
115
+
116
+ //_rEquivalentCumuProfitOrLossFinalNormYear, 等效年化報酬率越高越好, 須轉換至越低越好
117
+ let _rEquivalentCumuProfitOrLossFinalNormYear = 1 - rEquivalentCumuProfitOrLossFinalNormYear
118
+ // console.log('_rEquivalentCumuProfitOrLossFinalNormYear', _rEquivalentCumuProfitOrLossFinalNormYear)
119
+
120
+ // //rCumuProfitOrLossFinal
121
+ // let rCumuProfitOrLossFinal = p2r(summary.rCumuProfitOrLossFinal)
122
+
123
+ // //_rCumuProfitOrLossFinal, 盈虧越高須轉越低越好
124
+ // let _rCumuProfitOrLossFinal = 3000 - Math.max(rCumuProfitOrLossFinal, 0)
125
+ // if (_rCumuProfitOrLossFinal &lt; 0) {
126
+ // throw new Error(`最終盈虧比例[${_rCumuProfitOrLossFinal}]非預期過高`)
127
+ // }
128
+ // if (rCumuProfitOrLossFinal &lt;= 0) {
129
+ // _rCumuProfitOrLossFinal += 300000 - rCumuProfitOrLossFinal //懲罰值
130
+ // }
131
+
132
+ // //rDrawdownMax
133
+ // let rDrawdownMax = p2r(summary.rDrawdownMax)
134
+ // rDrawdownMax = Math.min(Math.max(rDrawdownMax, 0), 1)
135
+
136
+ // //_rDrawdownMax, 最大回撤率不用轉換, 越低越好
137
+ // let _rDrawdownMax = rDrawdownMax
138
+
139
+ // //rSharpe
140
+ // let rSharpe = w.cdbl(summary.rSharpe)
141
+
142
+ // //_rSharpe, 夏普值越高須轉越低越好
143
+ // let _rSharpe = 5 - Math.min(Math.max(rSharpe, 0), 5) //夏普值理論上可無限大, 故須限制範圍
144
+ // if (_rSharpe &lt; 0) {
145
+ // throw new Error(`夏普值[${rSharpe}]非預期過高`)
146
+ // }
147
+ // if (rSharpe &lt;= 0) {
148
+ // _rSharpe += 100000 - rSharpe //懲罰值
149
+ // }
150
+
151
+ //ratioWin
152
+ let ratioWin = p2r(summary.rWin)
153
+ ratioWin = Math.min(Math.max(ratioWin, 0), 1)
154
+
155
+ //_ratioWin, 勝率越高越好, 須轉換至越低越好
156
+ let _ratioWin = 1 - ratioWin
157
+
158
+ // //ratioKeep
159
+ // let ratioKeep = p2r(summary.rTradeAllMax)
160
+
161
+ //fitness
162
+ let fitness = 0
163
+ // fitness += 3 * _rCumuProfitOrLossFinal
164
+ // fitness += 2 * _rDrawdownMax
165
+ // fitness += 2 * _rSharpe
166
+ fitness += 2 * _ratioWin
167
+ fitness += 1 * _rEquivalentCumuProfitOrLossFinalNormYear
168
+ if (numTrade === 0) {
169
+ fitness += 1000000 //懲罰值
170
+ }
171
+ if (uCumuProfitOrLossFinal &lt;= 0) {
172
+ fitness += 1000000 //懲罰值
173
+ }
174
+ // console.log('fitness', fitness)
175
+
176
+ return fitness
177
+ }
178
+
179
+
180
+ export default calcFitness
181
+ </code></pre>
182
+ </article>
183
+ </section>
184
+
185
+
186
+
187
+
188
+
189
+
190
+ </div>
191
+
192
+ <br class="clear">
193
+
194
+ <footer>
195
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 04 2026 23:21:49 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
196
+ </footer>
197
+
198
+ <script>prettyPrint();</script>
199
+ <script src="scripts/polyfill.js"></script>
200
+ <script src="scripts/linenumber.js"></script>
201
+
202
+
203
+
204
+ </body>
205
+ </html>
@@ -0,0 +1,164 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+
5
+ <meta charset="utf-8">
6
+ <title>calcLevelNumTrade.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#calcFitness">calcFitness</a></li><li><a href="global.html#calcLevelNumTrade">calcLevelNumTrade</a></li><li><a href="global.html#cont">cont</a></li><li><a href="global.html#estimComps">estimComps</a></li><li><a href="global.html#estimFinder">estimFinder</a></li><li><a href="global.html#estimKeys">estimKeys</a></li><li><a href="global.html#estimPicks">estimPicks</a></li><li><a href="global.html#genSid">genSid</a></li><li><a href="global.html#genStrategyFileName">genStrategyFileName</a></li><li><a href="global.html#genTid">genTid</a></li><li><a href="global.html#nowTpeStr">nowTpeStr</a></li><li><a href="global.html#nowTpeStrp">nowTpeStrp</a></li><li><a href="global.html#ott">ott</a></li><li><a href="global.html#p2r">p2r</a></li><li><a href="global.html#readStrategies">readStrategies</a></li></ul>
33
+
34
+ </nav>
35
+
36
+ <div id="main">
37
+
38
+ <h1 class="page-title">calcLevelNumTrade.mjs</h1>
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+ <section>
47
+ <article>
48
+ <pre class="prettyprint source linenums"><code>import isnum from 'wsemi/src/isnum.mjs'
49
+ import cint from 'wsemi/src/cint.mjs'
50
+
51
+
52
+ /**
53
+ * 計算交易次數所屬級距代碼levelNumTrade
54
+ *
55
+ * 交易次數過少之策略統計意義不足,過多則屬高頻,故以級距分群,使不同交易次數規模之策略各自保留最佳者
56
+ * 級距對應為: &lt;=0為0,1-5為1,6-9為2,10-24為11,25-49為12,50-74為13,75-99為14,100-249為101,250-499為102,500-749為103,750-999為104,1000-1999為1001,2000-2999為1002,3000-3999為1003,4000-4999為1004,>=5000為100
57
+ * numTrade非數值時throw
58
+ *
59
+ * Unit Test: {@link https://github.com/yuda-lyu/w-trade-solve/blob/master/test/unit-calcLevelNumTrade.test.mjs Github}
60
+ * @function
61
+ * @param {Number} numTrade 輸入交易次數數值
62
+ * @returns {Number} 回傳級距代碼數值
63
+ * @example
64
+ *
65
+ * console.log(calcLevelNumTrade(0))
66
+ * // => 0
67
+ *
68
+ * console.log(calcLevelNumTrade(3))
69
+ * // => 1
70
+ *
71
+ * console.log(calcLevelNumTrade(30))
72
+ * // => 12
73
+ *
74
+ * console.log(calcLevelNumTrade(8000))
75
+ * // => 100
76
+ *
77
+ */
78
+ let calcLevelNumTrade = (numTrade) => {
79
+
80
+ if (!isnum(numTrade)) {
81
+ throw new Error(`numTrade[${numTrade}] is not a number`)
82
+ }
83
+ numTrade = cint(numTrade)
84
+
85
+ let levelNumTrade = 0
86
+ if (numTrade &lt;= 0) {
87
+ levelNumTrade = 0
88
+ }
89
+ else if (numTrade &lt;= 5) {
90
+ levelNumTrade = 1
91
+ }
92
+ else if (numTrade &lt;= 10 - 1) {
93
+ levelNumTrade = 2
94
+ }
95
+ else if (numTrade &lt;= 25 - 1) {
96
+ levelNumTrade = 11
97
+ }
98
+ else if (numTrade &lt;= 50 - 1) {
99
+ levelNumTrade = 12
100
+ }
101
+ else if (numTrade &lt;= 75 - 1) {
102
+ levelNumTrade = 13
103
+ }
104
+ else if (numTrade &lt;= 100 - 1) {
105
+ levelNumTrade = 14
106
+ }
107
+ else if (numTrade &lt;= 250 - 1) {
108
+ levelNumTrade = 101
109
+ }
110
+ else if (numTrade &lt;= 500 - 1) {
111
+ levelNumTrade = 102
112
+ }
113
+ else if (numTrade &lt;= 750 - 1) {
114
+ levelNumTrade = 103
115
+ }
116
+ else if (numTrade &lt;= 1000 - 1) {
117
+ levelNumTrade = 104
118
+ }
119
+ else if (numTrade &lt;= 2000 - 1) {
120
+ levelNumTrade = 1001
121
+ }
122
+ else if (numTrade &lt;= 3000 - 1) {
123
+ levelNumTrade = 1002
124
+ }
125
+ else if (numTrade &lt;= 4000 - 1) {
126
+ levelNumTrade = 1003
127
+ }
128
+ else if (numTrade &lt;= 5000 - 1) {
129
+ levelNumTrade = 1004
130
+ }
131
+ else {
132
+ levelNumTrade = 100
133
+ }
134
+
135
+ return levelNumTrade
136
+ }
137
+
138
+
139
+ export default calcLevelNumTrade
140
+ </code></pre>
141
+ </article>
142
+ </section>
143
+
144
+
145
+
146
+
147
+
148
+
149
+ </div>
150
+
151
+ <br class="clear">
152
+
153
+ <footer>
154
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 04 2026 23:21:49 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
155
+ </footer>
156
+
157
+ <script>prettyPrint();</script>
158
+ <script src="scripts/polyfill.js"></script>
159
+ <script src="scripts/linenumber.js"></script>
160
+
161
+
162
+
163
+ </body>
164
+ </html>
@@ -0,0 +1,94 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+
5
+ <meta charset="utf-8">
6
+ <title>cont.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#calcFitness">calcFitness</a></li><li><a href="global.html#calcLevelNumTrade">calcLevelNumTrade</a></li><li><a href="global.html#cont">cont</a></li><li><a href="global.html#estimComps">estimComps</a></li><li><a href="global.html#estimFinder">estimFinder</a></li><li><a href="global.html#estimKeys">estimKeys</a></li><li><a href="global.html#estimPicks">estimPicks</a></li><li><a href="global.html#genSid">genSid</a></li><li><a href="global.html#genStrategyFileName">genStrategyFileName</a></li><li><a href="global.html#genTid">genTid</a></li><li><a href="global.html#nowTpeStr">nowTpeStr</a></li><li><a href="global.html#nowTpeStrp">nowTpeStrp</a></li><li><a href="global.html#ott">ott</a></li><li><a href="global.html#p2r">p2r</a></li><li><a href="global.html#readStrategies">readStrategies</a></li></ul>
33
+
34
+ </nav>
35
+
36
+ <div id="main">
37
+
38
+ <h1 class="page-title">cont.mjs</h1>
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+ <section>
47
+ <article>
48
+ <pre class="prettyprint source linenums"><code>/**
49
+ * 共用常數
50
+ *
51
+ * dlmSeps為tid與sid內各段(mode與各key或各cond)之分隔字串
52
+ * dlmPkgs為策略檔名內各段(tid、levelNumTrade、rEquivalentCumuProfitOrLossFinalNormYear)之分隔字串
53
+ *
54
+ * @name cont
55
+ * @const
56
+ * @type {Object}
57
+ * @example
58
+ *
59
+ * console.log(cont)
60
+ * // => { dlmSeps: ' ║ ', dlmPkgs: ' ⊙ ' }
61
+ *
62
+ */
63
+ let r = {
64
+ dlmSeps: ' ║ ',
65
+ dlmPkgs: ' ⊙ ',
66
+ }
67
+
68
+
69
+ export default r
70
+ </code></pre>
71
+ </article>
72
+ </section>
73
+
74
+
75
+
76
+
77
+
78
+
79
+ </div>
80
+
81
+ <br class="clear">
82
+
83
+ <footer>
84
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 04 2026 23:21:49 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
85
+ </footer>
86
+
87
+ <script>prettyPrint();</script>
88
+ <script src="scripts/polyfill.js"></script>
89
+ <script src="scripts/linenumber.js"></script>
90
+
91
+
92
+
93
+ </body>
94
+ </html>
@@ -0,0 +1,190 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+
5
+ <meta charset="utf-8">
6
+ <title>estimComps.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#calcFitness">calcFitness</a></li><li><a href="global.html#calcLevelNumTrade">calcLevelNumTrade</a></li><li><a href="global.html#cont">cont</a></li><li><a href="global.html#estimComps">estimComps</a></li><li><a href="global.html#estimFinder">estimFinder</a></li><li><a href="global.html#estimKeys">estimKeys</a></li><li><a href="global.html#estimPicks">estimPicks</a></li><li><a href="global.html#genSid">genSid</a></li><li><a href="global.html#genStrategyFileName">genStrategyFileName</a></li><li><a href="global.html#genTid">genTid</a></li><li><a href="global.html#nowTpeStr">nowTpeStr</a></li><li><a href="global.html#nowTpeStrp">nowTpeStrp</a></li><li><a href="global.html#ott">ott</a></li><li><a href="global.html#p2r">p2r</a></li><li><a href="global.html#readStrategies">readStrategies</a></li></ul>
33
+
34
+ </nav>
35
+
36
+ <div id="main">
37
+
38
+ <h1 class="page-title">estimComps.mjs</h1>
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+ <section>
47
+ <article>
48
+ <pre class="prettyprint source linenums"><code>import get from 'lodash-es/get.js'
49
+ import map from 'lodash-es/map.js'
50
+ import size from 'lodash-es/size.js'
51
+ import cint from 'wsemi/src/cint.mjs'
52
+ import isestr from 'wsemi/src/isestr.mjs'
53
+ import randomIntsNdpRange from 'wsemi/src/randomIntsNdpRange.mjs'
54
+ import sep from 'wsemi/src/sep.mjs'
55
+ import estimPicks from './estimPicks.mjs'
56
+
57
+
58
+ /**
59
+ * 依指標組成comps隨機挑選keys,再率定各key之門檻與止盈止損,求解最佳策略
60
+ *
61
+ * comps為以逗號分隔之3個數字字串,依序代表由一般類(keysNorm)、指數類(keysIndex)與成交量類(keysVolumn)各隨機挑選之key個數,例如'2,1,0'代表挑2個一般類、1個指數類與0個成交量類
62
+ * 各類皆以randomIntsNdpRange不重複隨機取樣,故同一comps每次執行所挑之keys不同
63
+ * comps非3段時throw,其餘檢核與分類邏輯同estimPicks
64
+ *
65
+ * Unit Test: {@link https://github.com/yuda-lyu/w-trade-solve/blob/master/test/unit-estimComps.test.mjs Github}
66
+ * @function
67
+ * @param {Function} ott 輸入時區時間函數,傳入時間字串回傳dayjs時間物件,可用src/ott.mjs
68
+ * @param {Object} st 輸入設定物件,需可由opt.keySettings取得name、symbol與interval欄位
69
+ * @param {String} fdOhlc 輸入儲存K線(ohlc)序列資料夾字串
70
+ * @param {String} fdParam 輸入儲存指標參數序列資料夾字串
71
+ * @param {String} timeStart 輸入回測起始時間字串,格式'YYYY-MM-DDTHH:mm:ss'
72
+ * @param {String} timeEnd 輸入回測結束時間字串,格式'YYYY-MM-DDTHH:mm:ss'
73
+ * @param {String} mode 輸入交易方向字串,可選'long'或'short'
74
+ * @param {String} comps 輸入指標組成字串,為逗號分隔之3個數字,例如'2,1,0'
75
+ * @param {String} fdData 輸入儲存策略資料夾字串,不存在時自動建立
76
+ * @param {Object} [opt={}] 輸入設定物件,預設{},全部欄位皆傳遞至estimPicks
77
+ * @returns {Promise} 回傳Promise,resolve為undefined
78
+ * @example
79
+ *
80
+ * import ott from './src/ott.mjs'
81
+ *
82
+ * let st = {
83
+ * btc4hr: { name: 'btc', symbol: 'BTCUSDT', interval: '4hr' },
84
+ * }
85
+ *
86
+ * //comps='2,1,0', 挑2種一般類、1種指數類與0種成交量類
87
+ * await estimComps(ott, st, './data/ohlc', './data/param', '2022-07-01T00:00:00', '2025-04-08T00:00:00', 'long', '2,1,0', './data/strategy', {
88
+ * keySettings: 'btc4hr',
89
+ * })
90
+ *
91
+ */
92
+ let estimComps = async (ott, st, fdOhlc, fdParam, timeStart, timeEnd, mode, comps, fdData, opt = {}) => {
93
+
94
+ if (!isestr(fdOhlc)) {
95
+ throw new Error(`invalid fdOhlc[${fdOhlc}]`)
96
+ }
97
+ if (!isestr(fdParam)) {
98
+ throw new Error(`invalid fdParam[${fdParam}]`)
99
+ }
100
+ if (!isestr(timeStart)) {
101
+ throw new Error(`invalid timeStart[${timeStart}]`)
102
+ }
103
+ if (!isestr(timeEnd)) {
104
+ throw new Error(`invalid timeEnd[${timeEnd}]`)
105
+ }
106
+ if (mode !== 'long' &amp;&amp; mode !== 'short') {
107
+ throw new Error(`invalid mode[${mode}]`)
108
+ }
109
+ if (!isestr(comps)) {
110
+ throw new Error(`invalid comps[${comps}]`)
111
+ }
112
+ if (!isestr(fdData)) {
113
+ throw new Error(`invalid fdData[${fdData}]`)
114
+ }
115
+
116
+ //cs, 例如comps='2,1,0', 此為挑2種norm, 1種index, 0種volumn
117
+ let cs = sep(comps, ',')
118
+ if (size(cs) !== 3) {
119
+ throw new Error(`comps[${comps}]非預期`)
120
+ }
121
+ cs = map(cs, cint)
122
+ // console.log('cs', cs)
123
+
124
+ //pkn
125
+ let pkn = (arr, n) => {
126
+ let up = size(arr) - 1
127
+ let ks = randomIntsNdpRange(0, up, n)
128
+ let rs = map(ks, (k) => {
129
+ return get(arr, k)
130
+ })
131
+ return rs
132
+ }
133
+
134
+ //funPickKeys
135
+ let funPickKeys = ({ keysNorm, keysIndex, keysVolumn }) => {
136
+ let keys = []
137
+ if (cs[0] >= 1) {
138
+ keys = [
139
+ ...keys,
140
+ ...pkn(keysNorm, cs[0]),
141
+ ]
142
+ }
143
+ if (cs[1] >= 1) {
144
+ keys = [
145
+ ...keys,
146
+ ...pkn(keysIndex, cs[1]),
147
+ ]
148
+ }
149
+ if (cs[2] >= 1) {
150
+ keys = [
151
+ ...keys,
152
+ ...pkn(keysVolumn, cs[2]),
153
+ ]
154
+ }
155
+ // console.log('keys', keys)
156
+ return keys
157
+ }
158
+
159
+ //estimPicks
160
+ await estimPicks(ott, st, fdOhlc, fdParam, timeStart, timeEnd, mode, funPickKeys, fdData, opt)
161
+
162
+ }
163
+
164
+
165
+ export default estimComps
166
+ </code></pre>
167
+ </article>
168
+ </section>
169
+
170
+
171
+
172
+
173
+
174
+
175
+ </div>
176
+
177
+ <br class="clear">
178
+
179
+ <footer>
180
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 04 2026 23:21:49 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
181
+ </footer>
182
+
183
+ <script>prettyPrint();</script>
184
+ <script src="scripts/polyfill.js"></script>
185
+ <script src="scripts/linenumber.js"></script>
186
+
187
+
188
+
189
+ </body>
190
+ </html>