w-trade-solve 2.0.1 → 2.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.
- package/dist/w-trade-solve.umd.js +4 -4
- package/dist/w-trade-solve.umd.js.map +1 -1
- package/docs/calcFitness.mjs.html +1 -1
- package/docs/calcLevelNumTrade.mjs.html +1 -1
- package/docs/cont.mjs.html +1 -1
- package/docs/estimComps.mjs.html +1 -1
- package/docs/estimFinder.mjs.html +1 -1
- package/docs/estimKeys.mjs.html +132 -88
- package/docs/estimPicks.mjs.html +1 -1
- package/docs/genSid.mjs.html +1 -1
- package/docs/genStrategyFileName.mjs.html +1 -1
- package/docs/genTid.mjs.html +1 -1
- package/docs/global.html +124 -4
- package/docs/index.html +1 -1
- package/docs/ott.mjs.html +1 -1
- package/docs/p2r.mjs.html +1 -1
- package/docs/readStrategies.mjs.html +1 -1
- package/package.json +5 -5
- package/src/estimKeys.mjs +131 -87
- package/test/unit-estimKeys.test.mjs +193 -2
- package/toolg/gDistRollup.mjs +2 -0
|
@@ -192,7 +192,7 @@ export default calcFitness
|
|
|
192
192
|
<br class="clear">
|
|
193
193
|
|
|
194
194
|
<footer>
|
|
195
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
195
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 18 2026 14:52:32 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
196
196
|
</footer>
|
|
197
197
|
|
|
198
198
|
<script>prettyPrint();</script>
|
|
@@ -151,7 +151,7 @@ export default calcLevelNumTrade
|
|
|
151
151
|
<br class="clear">
|
|
152
152
|
|
|
153
153
|
<footer>
|
|
154
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
154
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 18 2026 14:52:32 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
155
155
|
</footer>
|
|
156
156
|
|
|
157
157
|
<script>prettyPrint();</script>
|
package/docs/cont.mjs.html
CHANGED
|
@@ -81,7 +81,7 @@ export default r
|
|
|
81
81
|
<br class="clear">
|
|
82
82
|
|
|
83
83
|
<footer>
|
|
84
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
84
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 18 2026 14:52:32 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
85
85
|
</footer>
|
|
86
86
|
|
|
87
87
|
<script>prettyPrint();</script>
|
package/docs/estimComps.mjs.html
CHANGED
|
@@ -182,7 +182,7 @@ export default estimComps
|
|
|
182
182
|
<br class="clear">
|
|
183
183
|
|
|
184
184
|
<footer>
|
|
185
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
185
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 18 2026 14:52:32 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
186
186
|
</footer>
|
|
187
187
|
|
|
188
188
|
<script>prettyPrint();</script>
|
|
@@ -189,7 +189,7 @@ export default estimFinder
|
|
|
189
189
|
<br class="clear">
|
|
190
190
|
|
|
191
191
|
<footer>
|
|
192
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
192
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 18 2026 14:52:32 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
193
193
|
</footer>
|
|
194
194
|
|
|
195
195
|
<script>prettyPrint();</script>
|
package/docs/estimKeys.mjs.html
CHANGED
|
@@ -61,6 +61,8 @@ import fsWriteJson from 'wsemi/src/fsWriteJson.mjs'
|
|
|
61
61
|
import isearr from 'wsemi/src/isearr.mjs'
|
|
62
62
|
import isestr from 'wsemi/src/isestr.mjs'
|
|
63
63
|
import isnum from 'wsemi/src/isnum.mjs'
|
|
64
|
+
import isbol from 'wsemi/src/isbol.mjs'
|
|
65
|
+
import isfun from 'wsemi/src/isfun.mjs'
|
|
64
66
|
import rang from 'wsemi/src/rang.mjs'
|
|
65
67
|
import wround from 'wsemi/src/round.mjs'
|
|
66
68
|
import omlRGA from 'w-optimization/src/omlRGA.mjs'
|
|
@@ -83,9 +85,9 @@ import genStrategyFileName from './genStrategyFileName.mjs'
|
|
|
83
85
|
*
|
|
84
86
|
* 設計變數為[止損比例, 止盈比例, ...各key之門檻],止損與止盈由opt.thsSl與opt.thsTp給予之百分比清單離散取值
|
|
85
87
|
* 各key門檻取值範圍為[-thLim,thLim]切為thLim*20段,並各自平移+vdir與-vdir(vdir=thLim*5)為兩組,使解值恆大於0代表'>'條件、恆小於0代表'<'條件,還原時再扣除平移值,故單一設計變數即同時涵蓋大於與小於兩種條件
|
|
86
|
-
* 以w-optimization之最佳化函數求解,由opt.methodOml指定演算法,各次計算皆以w-trade-backtest之runStrategy回測並經calcFitness
|
|
88
|
+
* 以w-optimization之最佳化函數求解,由opt.methodOml指定演算法,各次計算皆以w-trade-backtest之runStrategy回測並經calcFitness計算適應值;亦可由opt.funRunStrategyCustom注入自訂評估核心加速求解(如以w-trade-backtest之buildStrategyFastSession預算first-touch表與因子對位序列),注入僅回傳精簡欄位之核心時可配合opt.useRunStrategyBeforeSave於存檔前重跑完整回測,使落地summary維持完整欄位口徑;存檔前重跑後檔內numTrade、levelNumTrade、tkid、fitness與檔名皆由重跑之summary重新衍生,確保檔名與檔案內容同源一致;重算檔名與原檔名不同(評估核心與重跑結果跨級距)時,對新檔名重做存在檢查、身分驗證與優劣比較,新檔名已有更佳者則放棄本次寫入
|
|
87
89
|
* 各次計算結果若同時滿足交易次數、勝率與最終等效年化盈虧三門檻,則以genStrategyFileName產生檔名存入fdData;檔名為tkid(tid+交易次數級距)之純函數,故直接組出檔名查詢既有策略(O(1),不列舉全庫),同tkid已有策略時僅於最終等效年化盈虧更佳時原地覆寫,故同tkid恆僅一檔;覆寫前驗證舊檔內tkid、name與interval與本次一致,不一致代表雜湊碰撞,直接throw以避免無聲覆寫
|
|
88
|
-
* 策略檔內容除策略本體(tid、sid、name、symbol、interval、keyOhlc、mode、conds、settings)與summary、fitness外,另落地tkid、levelNumTrade、keys與solve區塊(timeStart、timeEnd、methodOml、thNumTrade、thRWin、thREquivalentCumuProfitOrLossFinalNormYear、thsTp、thsSl、timeSolved),使識別與求解條件欄位自足,不依賴檔名
|
|
90
|
+
* 策略檔內容除策略本體(tid、sid、name、symbol、interval、keyOhlc、mode、conds、settings)與summary、fitness外,另落地tkid、numTrade、levelNumTrade、keys與solve區塊(timeStart、timeEnd、methodOml、thNumTrade、thRWin、thREquivalentCumuProfitOrLossFinalNormYear、thsTp、thsSl、timeSolved),使識別與求解條件欄位自足,不依賴檔名
|
|
89
91
|
* opt除下列各欄位外,其餘欄位皆原樣傳遞至所選之最佳化函數,兩者欄位名稱無重疊,故可一併給予求解設定
|
|
90
92
|
* 各演算法共通之設定為NContiguous(最佳解連續未更新次數上限,預設100)、NRepeat、NCore、ModeOutLimit、UseRepeat、UseImmigration、LocalSearchMethod與funGetBetter、funGenerationBefore、funGenerationAfter三接口;族群數與迴圈數之欄位名稱各演算法不同,RGA與DE為Np與Ng、PSO為Np與Nl、HS為Ns與Ni、ACO為Na與Nl;另各演算法有其專屬超參數,如PSO之psoC1Start、RGA之rgaCrossover、DE之deF、HS之hsHMCR與ACO之acoAlphaStart等
|
|
91
93
|
* 預設之求解量甚大(單一key約需1萬7千次回測),僅需快速試算時可調小族群數與NContiguous
|
|
@@ -111,6 +113,9 @@ import genStrategyFileName from './genStrategyFileName.mjs'
|
|
|
111
113
|
* @param {Number} [opt.thNumTrade=1] 輸入策略須儲存之最少交易次數數值,預設1
|
|
112
114
|
* @param {Number} [opt.thRWin=0.5] 輸入策略須儲存之最低勝率比例數值,預設0.5
|
|
113
115
|
* @param {Number} [opt.thREquivalentCumuProfitOrLossFinalNormYear=0.15] 輸入策略須儲存之最低最終等效年化盈虧比例數值,預設0.15
|
|
116
|
+
* @param {Function} [opt.funRunStrategyCustom=null] 輸入自訂回測評估async函數,傳入{ott,strategy,funGetSeries}物件,須回傳{summary}且summary至少含numTrade、rWin、uEquityFinal與rEquivalentCumuProfitOrLossFinalNormYear四欄,各欄語義須與runStrategy等值,回傳之準確性由注入端負責;未給時採runStrategy,預設null
|
|
117
|
+
* @param {Boolean} [opt.useRunStrategyBeforeSave=false] 輸入存檔前是否重跑一次回測並以其summary重新衍生檔案內容與檔名布林值,注入僅回傳精簡欄位之評估核心時應設true以維持策略檔欄位口徑,求解搜索仍全程使用自訂函數不受影響,預設false
|
|
118
|
+
* @param {Function} [opt.funRunStrategyCustomBeforeSave=null] 輸入存檔前重跑用之自訂回測async函數,介面同opt.funRunStrategyCustom,僅於opt.useRunStrategyBeforeSave為true時生效,未給時採runStrategy,預設null
|
|
114
119
|
* @param {Boolean} [opt.useShowLog=false] 輸入是否顯示求解過程log布林值,預設false
|
|
115
120
|
* @returns {Promise} 回傳Promise,resolve為求解結果物件,含bestSolution(最佳解,內有ps設計變數陣列與fitness適應值)、stopMode(觸發停止之機制字串)、stopIteration(停止時之迴圈數)與stopExecutions(停止時之核心分析次數)等欄位
|
|
116
121
|
* @example
|
|
@@ -199,6 +204,12 @@ let estimKeys = async (ott, name, symbol, interval, fdOhlc, fdParam, timeStart,
|
|
|
199
204
|
if (!isnum(thREquivalentCumuProfitOrLossFinalNormYear)) {
|
|
200
205
|
thREquivalentCumuProfitOrLossFinalNormYear = 0.15
|
|
201
206
|
}
|
|
207
|
+
let funRunStrategyCustom = get(opt, 'funRunStrategyCustom', null)
|
|
208
|
+
let useRunStrategyBeforeSave = get(opt, 'useRunStrategyBeforeSave', null)
|
|
209
|
+
if (!isbol(useRunStrategyBeforeSave)) {
|
|
210
|
+
useRunStrategyBeforeSave = false
|
|
211
|
+
}
|
|
212
|
+
let funRunStrategyCustomBeforeSave = get(opt, 'funRunStrategyCustomBeforeSave', null)
|
|
202
213
|
let useShowLog = get(opt, 'useShowLog', null)
|
|
203
214
|
|
|
204
215
|
//provideData
|
|
@@ -301,6 +312,50 @@ let estimKeys = async (ott, name, symbol, interval, fdOhlc, fdParam, timeStart,
|
|
|
301
312
|
|
|
302
313
|
}
|
|
303
314
|
|
|
315
|
+
//checkSavable, 檢查指定檔名處是否可寫入策略: 無檔案或舊檔非合法json回傳true(直接寫入);
|
|
316
|
+
// 舊檔身分(tkid/name/interval)與本次不一致代表雜湊碰撞, 直接throw以避免無聲覆寫;
|
|
317
|
+
// 新等效年化盈虧較佳時回傳true(原地覆寫), 否則回傳false(保留既有較佳者)
|
|
318
|
+
let checkSavable = (fpStrategy, fnStrategy, tkid, rEquivalentCumuProfitOrLossFinalNormYearNew) => {
|
|
319
|
+
|
|
320
|
+
//check, 無同檔名策略, 新出現須儲存
|
|
321
|
+
if (!fsIsFile(fpStrategy)) {
|
|
322
|
+
return true
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
//dataOld
|
|
326
|
+
let dOld = fsReadJson(fpStrategy) //回傳{success}或{error}, 讀取或解析失敗時為null
|
|
327
|
+
let dataOld = get(dOld, 'success', null)
|
|
328
|
+
|
|
329
|
+
//check, 舊檔非合法json, 直接覆寫
|
|
330
|
+
if (dataOld === null) {
|
|
331
|
+
return true
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
//覆寫前驗證舊檔身分與本次一致, 不一致代表雜湊碰撞, 直接throw以避免無聲覆寫
|
|
335
|
+
let tkidOld = get(dataOld, 'tkid', '')
|
|
336
|
+
let nameOld = get(dataOld, 'name', '')
|
|
337
|
+
let intervalOld = get(dataOld, 'interval', '')
|
|
338
|
+
if ((isestr(tkidOld) && tkidOld !== tkid) || (isestr(nameOld) && nameOld !== name) || (isestr(intervalOld) && intervalOld !== interval)) {
|
|
339
|
+
throw new Error(`hash collision: fnStrategy[${fnStrategy}], tkidOld[${tkidOld}] vs tkid[${tkid}], nameOld[${nameOld}] vs name[${name}], intervalOld[${intervalOld}] vs interval[${interval}]`)
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
//rEquivalentCumuProfitOrLossFinalNormYearOld
|
|
343
|
+
let rEquivalentCumuProfitOrLossFinalNormYearOld = p2r(get(dataOld, 'summary.rEquivalentCumuProfitOrLossFinalNormYear', ''))
|
|
344
|
+
|
|
345
|
+
//check, 出現更好的等效盈虧比例, 原地覆寫
|
|
346
|
+
if (rEquivalentCumuProfitOrLossFinalNormYearNew > rEquivalentCumuProfitOrLossFinalNormYearOld) {
|
|
347
|
+
|
|
348
|
+
if (useShowLog) {
|
|
349
|
+
console.log(`覆寫較差策略...`, `${rEquivalentCumuProfitOrLossFinalNormYearNew} > ${rEquivalentCumuProfitOrLossFinalNormYearOld}`, fpStrategy)
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return true
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
//新等效盈虧未較佳, 不寫入
|
|
356
|
+
return false
|
|
357
|
+
}
|
|
358
|
+
|
|
304
359
|
//ifun, fitnessMin
|
|
305
360
|
let ifun = 0
|
|
306
361
|
let fitnessMin = 1e20
|
|
@@ -389,63 +444,69 @@ let estimKeys = async (ott, name, symbol, interval, fdOhlc, fdParam, timeStart,
|
|
|
389
444
|
}
|
|
390
445
|
|
|
391
446
|
//runStrategy
|
|
392
|
-
let r =
|
|
447
|
+
let r = null
|
|
448
|
+
if (isfun(funRunStrategyCustom)) {
|
|
449
|
+
r = await funRunStrategyCustom({ ott, strategy, funGetSeries })
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
r = await runStrategy(ott, strategy, funGetSeries)
|
|
453
|
+
}
|
|
393
454
|
// console.log(ifun, 'summary', r.summary)
|
|
394
455
|
|
|
395
|
-
//
|
|
396
|
-
let
|
|
456
|
+
//rEquivalentCumuProfitOrLossFinalNormYear
|
|
457
|
+
let rEquivalentCumuProfitOrLossFinalNormYear = p2r(r.summary.rEquivalentCumuProfitOrLossFinalNormYear)
|
|
397
458
|
|
|
398
459
|
//rWin
|
|
399
460
|
let rWin = p2r(r.summary.rWin)
|
|
400
461
|
|
|
401
|
-
//
|
|
402
|
-
|
|
462
|
+
//genRes
|
|
463
|
+
let genRes = (r) => {
|
|
403
464
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
// //rEquivalentCumuProfitOrLossFinal
|
|
408
|
-
// let rEquivalentCumuProfitOrLossFinal = p2r(r.summary.rEquivalentCumuProfitOrLossFinal)
|
|
409
|
-
|
|
410
|
-
//rEquivalentCumuProfitOrLossFinalNormYear
|
|
411
|
-
let rEquivalentCumuProfitOrLossFinalNormYear = p2r(r.summary.rEquivalentCumuProfitOrLossFinalNormYear)
|
|
465
|
+
//fitness
|
|
466
|
+
let fitness = calcFitness(strategy.settings, r.summary)
|
|
412
467
|
|
|
413
|
-
|
|
414
|
-
|
|
468
|
+
//numTrade
|
|
469
|
+
let numTrade = cint(r.summary.numTrade)
|
|
415
470
|
|
|
416
|
-
|
|
417
|
-
|
|
471
|
+
//levelNumTrade
|
|
472
|
+
let levelNumTrade = calcLevelNumTrade(numTrade)
|
|
418
473
|
|
|
419
|
-
|
|
420
|
-
|
|
474
|
+
//tkid
|
|
475
|
+
let tkid = `${tid}:${levelNumTrade}`
|
|
421
476
|
|
|
422
|
-
|
|
423
|
-
let res = {
|
|
477
|
+
return {
|
|
424
478
|
|
|
425
|
-
|
|
479
|
+
...strategy,
|
|
426
480
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
481
|
+
tkid,
|
|
482
|
+
numTrade,
|
|
483
|
+
levelNumTrade,
|
|
484
|
+
keys,
|
|
430
485
|
|
|
431
|
-
|
|
486
|
+
summary: r.summary,
|
|
432
487
|
|
|
433
|
-
|
|
488
|
+
fitness,
|
|
434
489
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
490
|
+
solve: {
|
|
491
|
+
timeStart,
|
|
492
|
+
timeEnd,
|
|
493
|
+
methodOml,
|
|
494
|
+
thNumTrade,
|
|
495
|
+
thRWin,
|
|
496
|
+
thREquivalentCumuProfitOrLossFinalNormYear,
|
|
497
|
+
thsTp,
|
|
498
|
+
thsSl,
|
|
499
|
+
timeSolved: ott().format('YYYY-MM-DDTHH:mm:ss'),
|
|
500
|
+
},
|
|
446
501
|
|
|
502
|
+
}
|
|
447
503
|
}
|
|
504
|
+
|
|
505
|
+
//res, 除策略本體與summary、fitness外, 落地tkid、levelNumTrade、keys與solve使欄位自足, 識別與求解條件不依賴檔名
|
|
506
|
+
let res = genRes(r)
|
|
448
507
|
// console.log(ifun, res)
|
|
508
|
+
|
|
509
|
+
//resBrief
|
|
449
510
|
let resBrief = {
|
|
450
511
|
|
|
451
512
|
'方向': res.mode,
|
|
@@ -468,20 +529,20 @@ let estimKeys = async (ott, name, symbol, interval, fdOhlc, fdParam, timeStart,
|
|
|
468
529
|
// console.log(ifun, resBrief)
|
|
469
530
|
|
|
470
531
|
//update fitnessMin
|
|
471
|
-
if (fitnessMin > fitness) {
|
|
532
|
+
if (fitnessMin > res.fitness) {
|
|
472
533
|
|
|
473
534
|
if (useShowLog) {
|
|
474
535
|
console.log(ifun, '更新最佳解', resBrief)
|
|
475
536
|
}
|
|
476
537
|
|
|
477
538
|
//update
|
|
478
|
-
fitnessMin = fitness
|
|
539
|
+
fitnessMin = res.fitness
|
|
479
540
|
|
|
480
541
|
}
|
|
481
542
|
|
|
482
543
|
//儲存可用參數組
|
|
483
544
|
if (
|
|
484
|
-
numTrade >= thNumTrade &&
|
|
545
|
+
res.numTrade >= thNumTrade &&
|
|
485
546
|
rWin >= thRWin &&
|
|
486
547
|
// rCumuProfitOrLossFinal > 0 &&
|
|
487
548
|
// rTradeAllMax <= 0.8 &&
|
|
@@ -500,69 +561,52 @@ let estimKeys = async (ott, name, symbol, interval, fdOhlc, fdParam, timeStart,
|
|
|
500
561
|
//fpStrategy
|
|
501
562
|
let fpStrategy = path.resolve(fdData, fnStrategy)
|
|
502
563
|
|
|
503
|
-
//b
|
|
504
|
-
let b =
|
|
564
|
+
//b, 檢查是否已有同tkid策略, 無檔案或舊檔非合法json即寫入, 已有者僅於新等效年化盈虧更佳時覆寫
|
|
565
|
+
let b = checkSavable(fpStrategy, fnStrategy, res.tkid, rEquivalentCumuProfitOrLossFinalNormYear)
|
|
505
566
|
|
|
506
|
-
//
|
|
507
|
-
|
|
567
|
+
//save
|
|
568
|
+
if (b) {
|
|
508
569
|
|
|
509
|
-
|
|
510
|
-
|
|
570
|
+
//useRunStrategyBeforeSave
|
|
571
|
+
if (useRunStrategyBeforeSave) {
|
|
511
572
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
573
|
+
if (isfun(funRunStrategyCustomBeforeSave)) {
|
|
574
|
+
r = await funRunStrategyCustomBeforeSave({ ott, strategy, funGetSeries })
|
|
575
|
+
}
|
|
576
|
+
else {
|
|
577
|
+
r = await runStrategy(ott, strategy, funGetSeries)
|
|
578
|
+
}
|
|
515
579
|
|
|
516
|
-
|
|
580
|
+
//res, 檔內全部衍生欄位由重跑之summary重新衍生, 確保檔案內容同源一致
|
|
581
|
+
res = genRes(r)
|
|
517
582
|
|
|
518
|
-
|
|
519
|
-
|
|
583
|
+
//fnStrategyRe, 以重跑之summary重算檔名, 使檔名級距與檔內同源
|
|
584
|
+
let fnStrategyRe = genStrategyFileName(name, interval, mode, keys, strategy.settings, r.summary)
|
|
520
585
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
//覆寫前驗證舊檔身分與本次一致, 不一致代表雜湊碰撞, 直接throw以避免無聲覆寫
|
|
525
|
-
let tkidOld = get(dataOld, 'tkid', '')
|
|
526
|
-
let nameOld = get(dataOld, 'name', '')
|
|
527
|
-
let intervalOld = get(dataOld, 'interval', '')
|
|
528
|
-
if ((isestr(tkidOld) && tkidOld !== tkid) || (isestr(nameOld) && nameOld !== name) || (isestr(intervalOld) && intervalOld !== interval)) {
|
|
529
|
-
throw new Error(`hash collision: fnStrategy[${fnStrategy}], tkidOld[${tkidOld}] vs tkid[${tkid}], nameOld[${nameOld}] vs name[${name}], intervalOld[${intervalOld}] vs interval[${interval}]`)
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
//rEquivalentCumuProfitOrLossFinalNormYearOld
|
|
533
|
-
let rEquivalentCumuProfitOrLossFinalNormYearOld = p2r(get(dataOld, 'summary.rEquivalentCumuProfitOrLossFinalNormYear', ''))
|
|
586
|
+
//check, 檔名有變代表評估核心與重跑結果跨級距, 新檔名須重做存在檢查/身分驗證/優劣比較, 不可沿用原檔名之通過結果
|
|
587
|
+
if (fnStrategyRe !== fnStrategy) {
|
|
534
588
|
|
|
535
|
-
|
|
536
|
-
|
|
589
|
+
//fnStrategy, fpStrategy
|
|
590
|
+
fnStrategy = fnStrategyRe
|
|
591
|
+
fpStrategy = path.resolve(fdData, fnStrategy)
|
|
537
592
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
}
|
|
541
|
-
b = true
|
|
593
|
+
//b, 以重跑之等效年化盈虧對新檔名重檢
|
|
594
|
+
b = checkSavable(fpStrategy, fnStrategy, res.tkid, p2r(get(r, 'summary.rEquivalentCumuProfitOrLossFinalNormYear', '')))
|
|
542
595
|
|
|
543
596
|
}
|
|
544
597
|
|
|
545
598
|
}
|
|
546
599
|
|
|
547
|
-
}
|
|
548
|
-
else {
|
|
549
|
-
|
|
550
|
-
//新出現須儲存
|
|
551
|
-
b = true
|
|
552
|
-
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
//save
|
|
556
|
-
if (b) {
|
|
557
|
-
|
|
558
600
|
//fsWriteJson
|
|
559
|
-
|
|
601
|
+
if (b) {
|
|
602
|
+
fsWriteJson(fpStrategy, res, { useFormat: true })
|
|
603
|
+
}
|
|
560
604
|
|
|
561
605
|
}
|
|
562
606
|
|
|
563
607
|
}
|
|
564
608
|
|
|
565
|
-
return fitness
|
|
609
|
+
return res.fitness
|
|
566
610
|
}
|
|
567
611
|
|
|
568
612
|
//oml
|
|
@@ -617,7 +661,7 @@ export default estimKeys
|
|
|
617
661
|
<br class="clear">
|
|
618
662
|
|
|
619
663
|
<footer>
|
|
620
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
664
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 18 2026 14:52:32 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
621
665
|
</footer>
|
|
622
666
|
|
|
623
667
|
<script>prettyPrint();</script>
|
package/docs/estimPicks.mjs.html
CHANGED
|
@@ -192,7 +192,7 @@ export default estimPicks
|
|
|
192
192
|
<br class="clear">
|
|
193
193
|
|
|
194
194
|
<footer>
|
|
195
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
195
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 18 2026 14:52:32 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
196
196
|
</footer>
|
|
197
197
|
|
|
198
198
|
<script>prettyPrint();</script>
|
package/docs/genSid.mjs.html
CHANGED
|
@@ -112,7 +112,7 @@ export default genSid
|
|
|
112
112
|
<br class="clear">
|
|
113
113
|
|
|
114
114
|
<footer>
|
|
115
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
115
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 18 2026 14:52:32 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
116
116
|
</footer>
|
|
117
117
|
|
|
118
118
|
<script>prettyPrint();</script>
|
|
@@ -122,7 +122,7 @@ export default genStrategyFileName
|
|
|
122
122
|
<br class="clear">
|
|
123
123
|
|
|
124
124
|
<footer>
|
|
125
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
125
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 18 2026 14:52:32 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
126
126
|
</footer>
|
|
127
127
|
|
|
128
128
|
<script>prettyPrint();</script>
|
package/docs/genTid.mjs.html
CHANGED
|
@@ -100,7 +100,7 @@ export default genTid
|
|
|
100
100
|
<br class="clear">
|
|
101
101
|
|
|
102
102
|
<footer>
|
|
103
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
103
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 18 2026 14:52:32 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
104
104
|
</footer>
|
|
105
105
|
|
|
106
106
|
<script>prettyPrint();</script>
|
package/docs/global.html
CHANGED
|
@@ -1841,9 +1841,9 @@ await estimFinder(ott, 'btc', 'BTCUSDT', '4hr', './data/ohlc', './data/param', '
|
|
|
1841
1841
|
<dd class="tag-description"><ul class="dummy"><li><p>針對指定keys率定各key之門檻與止盈止損,求解最佳策略</p>
|
|
1842
1842
|
<p>設計變數為[止損比例, 止盈比例, ...各key之門檻],止損與止盈由opt.thsSl與opt.thsTp給予之百分比清單離散取值
|
|
1843
1843
|
各key門檻取值範圍為[-thLim,thLim]切為thLim<em>20段,並各自平移+vdir與-vdir(vdir=thLim</em>5)為兩組,使解值恆大於0代表'>'條件、恆小於0代表'<'條件,還原時再扣除平移值,故單一設計變數即同時涵蓋大於與小於兩種條件
|
|
1844
|
-
以w-optimization之最佳化函數求解,由opt.methodOml指定演算法,各次計算皆以w-trade-backtest之runStrategy回測並經calcFitness
|
|
1844
|
+
以w-optimization之最佳化函數求解,由opt.methodOml指定演算法,各次計算皆以w-trade-backtest之runStrategy回測並經calcFitness計算適應值;亦可由opt.funRunStrategyCustom注入自訂評估核心加速求解(如以w-trade-backtest之buildStrategyFastSession預算first-touch表與因子對位序列),注入僅回傳精簡欄位之核心時可配合opt.useRunStrategyBeforeSave於存檔前重跑完整回測,使落地summary維持完整欄位口徑;存檔前重跑後檔內numTrade、levelNumTrade、tkid、fitness與檔名皆由重跑之summary重新衍生,確保檔名與檔案內容同源一致;重算檔名與原檔名不同(評估核心與重跑結果跨級距)時,對新檔名重做存在檢查、身分驗證與優劣比較,新檔名已有更佳者則放棄本次寫入
|
|
1845
1845
|
各次計算結果若同時滿足交易次數、勝率與最終等效年化盈虧三門檻,則以genStrategyFileName產生檔名存入fdData;檔名為tkid(tid+交易次數級距)之純函數,故直接組出檔名查詢既有策略(O(1),不列舉全庫),同tkid已有策略時僅於最終等效年化盈虧更佳時原地覆寫,故同tkid恆僅一檔;覆寫前驗證舊檔內tkid、name與interval與本次一致,不一致代表雜湊碰撞,直接throw以避免無聲覆寫
|
|
1846
|
-
策略檔內容除策略本體(tid、sid、name、symbol、interval、keyOhlc、mode、conds、settings)與summary、fitness外,另落地tkid、levelNumTrade、keys與solve區塊(timeStart、timeEnd、methodOml、thNumTrade、thRWin、thREquivalentCumuProfitOrLossFinalNormYear、thsTp、thsSl、timeSolved),使識別與求解條件欄位自足,不依賴檔名
|
|
1846
|
+
策略檔內容除策略本體(tid、sid、name、symbol、interval、keyOhlc、mode、conds、settings)與summary、fitness外,另落地tkid、numTrade、levelNumTrade、keys與solve區塊(timeStart、timeEnd、methodOml、thNumTrade、thRWin、thREquivalentCumuProfitOrLossFinalNormYear、thsTp、thsSl、timeSolved),使識別與求解條件欄位自足,不依賴檔名
|
|
1847
1847
|
opt除下列各欄位外,其餘欄位皆原樣傳遞至所選之最佳化函數,兩者欄位名稱無重疊,故可一併給予求解設定
|
|
1848
1848
|
各演算法共通之設定為NContiguous(最佳解連續未更新次數上限,預設100)、NRepeat、NCore、ModeOutLimit、UseRepeat、UseImmigration、LocalSearchMethod與funGetBetter、funGenerationBefore、funGenerationAfter三接口;族群數與迴圈數之欄位名稱各演算法不同,RGA與DE為Np與Ng、PSO為Np與Nl、HS為Ns與Ni、ACO為Na與Nl;另各演算法有其專屬超參數,如PSO之psoC1Start、RGA之rgaCrossover、DE之deF、HS之hsHMCR與ACO之acoAlphaStart等
|
|
1849
1849
|
預設之求解量甚大(單一key約需1萬7千次回測),僅需快速試算時可調小族群數與NContiguous
|
|
@@ -1854,7 +1854,7 @@ name、symbol、interval、fdOhlc、fdParam、timeStart、timeEnd、keys、fdDat
|
|
|
1854
1854
|
|
|
1855
1855
|
<dt class="tag-source">Source:</dt>
|
|
1856
1856
|
<dd class="tag-source"><ul class="dummy"><li>
|
|
1857
|
-
<a href="estimKeys.mjs.html">estimKeys.mjs</a>, <a href="estimKeys.mjs.html#
|
|
1857
|
+
<a href="estimKeys.mjs.html">estimKeys.mjs</a>, <a href="estimKeys.mjs.html#line103">line 103</a>
|
|
1858
1858
|
</li></ul></dd>
|
|
1859
1859
|
|
|
1860
1860
|
|
|
@@ -2656,6 +2656,126 @@ console.log(mQuick.stopExecutions) //核心分析次數, 較預設設定大幅
|
|
|
2656
2656
|
|
|
2657
2657
|
|
|
2658
2658
|
|
|
2659
|
+
<tr>
|
|
2660
|
+
|
|
2661
|
+
<td class="name"><code>funRunStrategyCustom</code></td>
|
|
2662
|
+
|
|
2663
|
+
|
|
2664
|
+
<td class="type">
|
|
2665
|
+
|
|
2666
|
+
|
|
2667
|
+
<span class="param-type">function</span>
|
|
2668
|
+
|
|
2669
|
+
|
|
2670
|
+
|
|
2671
|
+
|
|
2672
|
+
</td>
|
|
2673
|
+
|
|
2674
|
+
|
|
2675
|
+
<td class="attributes">
|
|
2676
|
+
|
|
2677
|
+
<optional><br>
|
|
2678
|
+
|
|
2679
|
+
|
|
2680
|
+
|
|
2681
|
+
|
|
2682
|
+
|
|
2683
|
+
</td>
|
|
2684
|
+
|
|
2685
|
+
|
|
2686
|
+
|
|
2687
|
+
<td class="default">
|
|
2688
|
+
|
|
2689
|
+
<code>null</code>
|
|
2690
|
+
|
|
2691
|
+
</td>
|
|
2692
|
+
|
|
2693
|
+
|
|
2694
|
+
<td class="description last"><p>輸入自訂回測評估async函數,傳入{ott,strategy,funGetSeries}物件,須回傳{summary}且summary至少含numTrade、rWin、uEquityFinal與rEquivalentCumuProfitOrLossFinalNormYear四欄,各欄語義須與runStrategy等值,回傳之準確性由注入端負責;未給時採runStrategy,預設null</p></td>
|
|
2695
|
+
</tr>
|
|
2696
|
+
|
|
2697
|
+
|
|
2698
|
+
|
|
2699
|
+
<tr>
|
|
2700
|
+
|
|
2701
|
+
<td class="name"><code>useRunStrategyBeforeSave</code></td>
|
|
2702
|
+
|
|
2703
|
+
|
|
2704
|
+
<td class="type">
|
|
2705
|
+
|
|
2706
|
+
|
|
2707
|
+
<span class="param-type">Boolean</span>
|
|
2708
|
+
|
|
2709
|
+
|
|
2710
|
+
|
|
2711
|
+
|
|
2712
|
+
</td>
|
|
2713
|
+
|
|
2714
|
+
|
|
2715
|
+
<td class="attributes">
|
|
2716
|
+
|
|
2717
|
+
<optional><br>
|
|
2718
|
+
|
|
2719
|
+
|
|
2720
|
+
|
|
2721
|
+
|
|
2722
|
+
|
|
2723
|
+
</td>
|
|
2724
|
+
|
|
2725
|
+
|
|
2726
|
+
|
|
2727
|
+
<td class="default">
|
|
2728
|
+
|
|
2729
|
+
<code>false</code>
|
|
2730
|
+
|
|
2731
|
+
</td>
|
|
2732
|
+
|
|
2733
|
+
|
|
2734
|
+
<td class="description last"><p>輸入存檔前是否重跑一次回測並以其summary重新衍生檔案內容與檔名布林值,注入僅回傳精簡欄位之評估核心時應設true以維持策略檔欄位口徑,求解搜索仍全程使用自訂函數不受影響,預設false</p></td>
|
|
2735
|
+
</tr>
|
|
2736
|
+
|
|
2737
|
+
|
|
2738
|
+
|
|
2739
|
+
<tr>
|
|
2740
|
+
|
|
2741
|
+
<td class="name"><code>funRunStrategyCustomBeforeSave</code></td>
|
|
2742
|
+
|
|
2743
|
+
|
|
2744
|
+
<td class="type">
|
|
2745
|
+
|
|
2746
|
+
|
|
2747
|
+
<span class="param-type">function</span>
|
|
2748
|
+
|
|
2749
|
+
|
|
2750
|
+
|
|
2751
|
+
|
|
2752
|
+
</td>
|
|
2753
|
+
|
|
2754
|
+
|
|
2755
|
+
<td class="attributes">
|
|
2756
|
+
|
|
2757
|
+
<optional><br>
|
|
2758
|
+
|
|
2759
|
+
|
|
2760
|
+
|
|
2761
|
+
|
|
2762
|
+
|
|
2763
|
+
</td>
|
|
2764
|
+
|
|
2765
|
+
|
|
2766
|
+
|
|
2767
|
+
<td class="default">
|
|
2768
|
+
|
|
2769
|
+
<code>null</code>
|
|
2770
|
+
|
|
2771
|
+
</td>
|
|
2772
|
+
|
|
2773
|
+
|
|
2774
|
+
<td class="description last"><p>輸入存檔前重跑用之自訂回測async函數,介面同opt.funRunStrategyCustom,僅於opt.useRunStrategyBeforeSave為true時生效,未給時採runStrategy,預設null</p></td>
|
|
2775
|
+
</tr>
|
|
2776
|
+
|
|
2777
|
+
|
|
2778
|
+
|
|
2659
2779
|
<tr>
|
|
2660
2780
|
|
|
2661
2781
|
<td class="name"><code>useShowLog</code></td>
|
|
@@ -5249,7 +5369,7 @@ console.log(readStrategies(fd))
|
|
|
5249
5369
|
<br class="clear">
|
|
5250
5370
|
|
|
5251
5371
|
<footer>
|
|
5252
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
5372
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 18 2026 14:52:32 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
5253
5373
|
</footer>
|
|
5254
5374
|
|
|
5255
5375
|
<script>prettyPrint();</script>
|
package/docs/index.html
CHANGED
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
<br class="clear">
|
|
72
72
|
|
|
73
73
|
<footer>
|
|
74
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
74
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 18 2026 14:52:32 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
75
75
|
</footer>
|
|
76
76
|
|
|
77
77
|
<script>prettyPrint();</script>
|
package/docs/ott.mjs.html
CHANGED
|
@@ -124,7 +124,7 @@ export { ott, nowTpeStr, nowTpeStrp }
|
|
|
124
124
|
<br class="clear">
|
|
125
125
|
|
|
126
126
|
<footer>
|
|
127
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
127
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 18 2026 14:52:32 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
128
128
|
</footer>
|
|
129
129
|
|
|
130
130
|
<script>prettyPrint();</script>
|
package/docs/p2r.mjs.html
CHANGED
|
@@ -98,7 +98,7 @@ export default p2r
|
|
|
98
98
|
<br class="clear">
|
|
99
99
|
|
|
100
100
|
<footer>
|
|
101
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
101
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 18 2026 14:52:32 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
102
102
|
</footer>
|
|
103
103
|
|
|
104
104
|
<script>prettyPrint();</script>
|
|
@@ -274,7 +274,7 @@ export default readStrategies
|
|
|
274
274
|
<br class="clear">
|
|
275
275
|
|
|
276
276
|
<footer>
|
|
277
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
277
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 18 2026 14:52:32 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
278
278
|
</footer>
|
|
279
279
|
|
|
280
280
|
<script>prettyPrint();</script>
|