import isNumber from 'lodash-es/isNumber.js'
import get from 'lodash-es/get.js'
import size from 'lodash-es/size.js'
import slice from 'lodash-es/slice.js'
import sumBy from 'lodash-es/sumBy.js'
import each from 'lodash-es/each.js'
import pickValue from './pickValue.mjs'
/**
* 計算各週期之移動平均MA(Moving Average)
*
* 各週期len為該期涵蓋之K線根數(以4hr K線為基準,1day=6根),資料筆數不足該期len時,該期vs為空陣列
* 各期第1筆對應輸入之第len根,其後逐根對齊至最後一根
*
* Unit Test: {@link https://github.com/yuda-lyu/w-data-trade/blob/master/test/unit-calcMa.test.mjs Github}
* @function
* @param {Array} arr 輸入K線陣列,各元素需含time與計算所用之數值欄位
* @param {String} key 輸入計算所用數值欄位名稱字串,例如'Close'
* @param {Object} [opt={}] 輸入設定物件,預設{}
* @param {Boolean} [opt.norm=false] 輸入是否將param改為均線與現值之偏離比例(MA-現值)/現值布林值,預設false
* @returns {Promise} 回傳Promise,resolve為各期結果陣列,各元素為{period,len,vs},vs內各元素為{time,param}
* @example
*
* let arr = [
* { time: '2020-01-01T00:00:00', Close: 7173.32 },
* { time: '2020-01-01T04:00:00', Close: 7195.23 },
* { time: '2020-01-01T08:00:00', Close: 7225.01 },
* { time: '2020-01-01T12:00:00', Close: 7209.83 },
* { time: '2020-01-01T16:00:00', Close: 7188.77 },
* { time: '2020-01-01T20:00:00', Close: 7200.85 },
* ]
*
* calcMa(arr, 'Close')
* .then((rs) => {
* console.log(rs[0])
* // => {
* // period: '1day',
* // len: 6,
* // vs: [ { time: '2020-01-01T20:00:00', param: 7198.835 } ]
* // }
* })
*
*/
let calcMa = (() => {
let kp = {
'1day': 6, // 1 day = 6 * 4 hours
'2day': 12, // 2 days = 12 * 4 hours
'4day': 24, // 4 days = 24 * 4 hours
'7day': 42, // 7 days = 42 * 4 hours
'15day': 90, // 15 days = 90 * 4 hours
'30day': 180, // 30 days = 180 * 4 hours
}
let caMa = (vs, len, opt = {}) => {
//check
if (!isNumber(len)) {
throw new Error(`len is not a number`)
}
//norm
let norm = get(opt, 'norm', false)
//n
let n = size(vs)
//check
if (n < len) {
return []
}
//rs
let rs = []
for (let i = len - 1; i < n; i++) {
//indStart
let indStart = i - len + 1
indStart = Math.max(indStart, 0)
//indEnd
let indEnd = i + 1
indEnd = Math.min(indEnd, n)
//prs
let prs = slice(vs, indStart, indEnd)
// console.log('prs', prs)
//sum
let sum = sumBy(prs, 'value')
// console.log('sum', sum)
//ma
let ma = sum / len
//diffMa
let diffMa = ma - vs[i].value //ma-現在
//ratioDiffMa
let ratioDiffMa = 0
if (vs[i].value !== 0) {
ratioDiffMa = diffMa / vs[i].value
}
//param
let param = ma
if (norm) {
param = ratioDiffMa
}
//r
let r = {
time: vs[i].time,
param,
}
//push
rs.push(r)
}
return rs
}
let caMas = (vs, opt = {}) => {
//rrs
let rrs = []
each(kp, (len, period) => {
//caMa
let rs = caMa(vs, len, opt)
//push
rrs.push({
period,
len,
vs: rs,
})
})
return rrs
}
let calcMa = async (arr, key, opt = {}) => {
// arr = [
// {"time":"2020-01-01T00:00:00","Open":7195,"High":7225.62,"Low":7145.01,"Close":7173.32,"Volumn":4657.972543,"CloseTime":"2020-01-01T03:59:59","QuoteAssetVolume":33441599.81960844,"NumberOfTrades":46046,"TakerBuyBaseAssetVolume":2161.591103,"TakerBuyQuoteAssetVolume":15520451.66291961},
// {"time":"2020-01-01T04:00:00","Open":7173.75,"High":7208.41,"Low":7165.1,"Close":7195.23,"Volumn":2091.720176,"CloseTime":"2020-01-01T07:59:59","QuoteAssetVolume":15032938.06298061,"NumberOfTrades":29738,"TakerBuyBaseAssetVolume":1010.628114,"TakerBuyQuoteAssetVolume":7263338.98247078},
// {"time":"2020-01-01T08:00:00","Open":7195.24,"High":7245,"Low":7175.46,"Close":7225.01,"Volumn":2833.74918,"CloseTime":"2020-01-01T11:59:59","QuoteAssetVolume":20445895.8017956,"NumberOfTrades":32476,"TakerBuyBaseAssetVolume":1548.865619,"TakerBuyQuoteAssetVolume":11176594.41972043},
// {"time":"2020-01-01T12:00:00","Open":7225,"High":7236.27,"Low":7199.11,"Close":7209.83,"Volumn":2061.295051,"CloseTime":"2020-01-01T15:59:59","QuoteAssetVolume":14890182.27509305,"NumberOfTrades":29991,"TakerBuyBaseAssetVolume":1049.711236,"TakerBuyQuoteAssetVolume":7582850.37593562},
// ...
// ]
//pickValue
let vs = pickValue(arr, key) //轉為 { time, value }
//caMas
let rs = caMas(vs, opt)
return rs
}
return calcMa
})()
export default calcMa