import each from 'lodash-es/each.js'
import get from 'lodash-es/get.js'
import isestr from 'wsemi/src/isestr.mjs'
import isfun from 'wsemi/src/isfun.mjs'
import dataProvide from 'w-data-tdprovide'
import estimKeys from './estimKeys.mjs'
/**
* 由fdParam內全部指標key分類後挑選keys,再率定各key之門檻與止盈止損,求解最佳策略
*
* 先由fdParam列舉全部指標key,並依名稱分為3類: 開頭為'index_'者為keysIndex(指數類)、含'_vbs_'者為keysVolumn(成交量類)、其餘為keysNorm(一般類)
* 分類後各類可經opt內對應之過濾函數再行篩選,接著呼叫funPickKeys由3類挑出待率定之keys,最後交由estimKeys求解
* name、symbol、interval、fdOhlc、fdParam、timeStart、timeEnd、fdData無效或mode非'long'或'short'或funPickKeys非函數時throw
*
* Unit Test: {@link https://github.com/yuda-lyu/w-trade-solve/blob/master/test/unit-estimPicks.test.mjs Github}
* @function
* @param {Function} ott 輸入時區時間函數,傳入時間字串回傳dayjs時間物件,可用src/ott.mjs
* @param {String} name 輸入幣種名稱字串,例如'btc'
* @param {String} symbol 輸入交易對名稱字串,例如'BTCUSDT'
* @param {String} interval 輸入K線週期字串,例如'4hr'
* @param {String} fdOhlc 輸入儲存K線(ohlc)序列資料夾字串
* @param {String} fdParam 輸入儲存指標參數序列資料夾字串
* @param {String} timeStart 輸入回測起始時間字串,格式'YYYY-MM-DDTHH:mm:ss'
* @param {String} timeEnd 輸入回測結束時間字串,格式'YYYY-MM-DDTHH:mm:ss'
* @param {String} mode 輸入交易方向字串,可選'long'或'short'
* @param {Function} funPickKeys 輸入挑選keys函數,傳入{keysNorm,keysIndex,keysVolumn}物件,回傳待率定之指標key字串陣列
* @param {String} fdData 輸入儲存策略資料夾字串,不存在時自動建立
* @param {Object} [opt={}] 輸入設定物件,預設{},其餘欄位皆傳遞至estimKeys
* @param {Function} [opt.funFilterKeysNorm=null] 輸入過濾一般類key之async函數,傳入keysNorm陣列回傳過濾後陣列,預設null
* @param {Function} [opt.funFilterKeysIndex=null] 輸入過濾指數類key之async函數,傳入keysIndex陣列回傳過濾後陣列,預設null
* @param {Function} [opt.funFilterKeysVolumn=null] 輸入過濾成交量類key之async函數,傳入keysVolumn陣列回傳過濾後陣列,預設null
* @returns {Promise} 回傳Promise,resolve為undefined
* @example
*
* import ott from './src/ott.mjs'
*
* //funPickKeys, 由一般類挑第1個key為待率定key
* let funPickKeys = ({ keysNorm, keysIndex, keysVolumn }) => {
* return [keysNorm[0]]
* }
*
* await estimPicks(ott, 'btc', 'BTCUSDT', '4hr', './data/ohlc', './data/param', '2022-07-01T00:00:00', '2025-04-08T00:00:00', 'long', funPickKeys, './data/strategy', {})
*
*/
let estimPicks = async (ott, name, symbol, interval, fdOhlc, fdParam, timeStart, timeEnd, mode, funPickKeys, fdData, opt = {}) => {
if (!isestr(name)) {
throw new Error(`invalid name[${name}]`)
}
if (!isestr(symbol)) {
throw new Error(`invalid symbol[${symbol}]`)
}
if (!isestr(interval)) {
throw new Error(`invalid interval[${interval}]`)
}
if (!isestr(fdOhlc)) {
throw new Error(`invalid fdOhlc[${fdOhlc}]`)
}
if (!isestr(fdParam)) {
throw new Error(`invalid fdParam[${fdParam}]`)
}
if (!isestr(timeStart)) {
throw new Error(`invalid timeStart[${timeStart}]`)
}
if (!isestr(timeEnd)) {
throw new Error(`invalid timeEnd[${timeEnd}]`)
}
if (mode !== 'long' && mode !== 'short') {
throw new Error(`invalid mode[${mode}]`)
}
if (!isfun(funPickKeys)) {
throw new Error(`funPickKeys is not a function`)
}
if (!isestr(fdData)) {
throw new Error(`invalid fdData[${fdData}]`)
}
let funFilterKeysNorm = get(opt, 'funFilterKeysNorm', null)
let funFilterKeysIndex = get(opt, 'funFilterKeysIndex', null)
let funFilterKeysVolumn = get(opt, 'funFilterKeysVolumn', null)
//provideData
let provideData = dataProvide(fdOhlc, fdParam)
//keysParam
let keysParam = provideData.getKeysParam()
// console.log('keysParam', keysParam)
//keysIndex, keysVolumn, keysNorm
let keysIndex = []
let keysVolumn = []
let keysNorm = []
each(keysParam, (v) => {
let b1 = v.indexOf('index_') === 0
let b2 = v.indexOf('_vbs_') >= 0
let b3 = !(b1 || b2)
if (b1) {
keysIndex.push(v)
}
else if (b2) {
keysVolumn.push(v)
}
else if (b3) {
keysNorm.push(v)
}
})
// console.log('keysIndex', keysIndex)
// console.log('keysVolumn', keysVolumn)
// console.log('keysNorm', keysNorm)
// console.log(size(keysIndex) + size(keysVolumn) + size(keysNorm))
if (isfun(funFilterKeysNorm)) {
keysNorm = await funFilterKeysNorm(keysNorm)
}
if (isfun(funFilterKeysIndex)) {
keysIndex = await funFilterKeysIndex(keysIndex)
}
if (isfun(funFilterKeysVolumn)) {
keysVolumn = await funFilterKeysVolumn(keysVolumn)
}
//keys
let keys = funPickKeys({ keysNorm, keysIndex, keysVolumn })
// console.log('keys', keys)
//estimKeys
await estimKeys(ott, name, symbol, interval, fdOhlc, fdParam, timeStart, timeEnd, mode, keys, fdData, opt)
}
export default estimPicks