Type/to search
8
Follow
1361
Followers
Open source FMZ Quant TA library, learn to use (with Javascript/Python/C++ versions)
Original
Created 2023-07-12 15:55:21  Updated 2025-01-08 21:35:42
 0
 1107

img

Open source FMZ Quant TA library, learn to use (with JavascriptPythonC++ versions)

The code is the best commentary, how can you say you know how to use an indicator if you don't know how it is generated.
The following code is handcrafted by myself when I transitioned from being a programmer to the finance industry, without any copy-pasting. I hope it will be helpful for beginners.

javascript
var Std = { _skip: function(arr, period) { var j = 0; for (var k = 0; j < arr.length; j++) { if (!isNaN(arr[j])) k++; if (k == period) break; } return j; }, _sum: function(arr, num) { var sum = 0.0; for (var i = 0; i < num; i++) { if (!isNaN(arr[i])) { sum += arr[i]; } } return sum; }, _avg: function(arr, num) { var n = 0; var sum = 0.0; for (var i = 0; i < num; i++) { if (!isNaN(arr[i])) { sum += arr[i]; n++; } } return sum / n; }, _zeros: function(len) { var n = []; for (var i = 0; i < len; i++) { n.push(0.0); } return n; }, _set: function(arr, start, end, value) { var e = Math.min(arr.length, end); for (var i = start; i < e; i++) { arr[i] = value; } }, _diff: function(a, b) { var d = []; for (var i = 0; i < b.length; i++) { if (isNaN(a[i]) || isNaN(b[i])) { d.push(NaN); } else { d.push(a[i] - b[i]); } } return d; }, _move_diff: function(a) { var d = []; for (var i = 1; i < a.length; i++) { d.push(a[i] - a[i - 1]); } return d; }, _sma: function(S, period) { var R = Std._zeros(S.length); var j = Std._skip(S, period); Std._set(R, 0, j, NaN); if (j < S.length) { var sum = 0; for (var i = j; i < S.length; i++) { if (i == j) { sum = Std._sum(S, i + 1); } else { sum += S[i] - S[i - period]; } R[i] = sum / period; } } return R; }, _smma: function(S, period) { var R = Std._zeros(S.length); var j = Std._skip(S, period); Std._set(R, 0, j, NaN); if (j < S.length) { R[j] = Std._avg(S, j + 1); for (var i = j + 1; i < S.length; i++) { R[i] = (R[i - 1] * (period - 1) + S[i]) / period; } } return R; }, _ema: function(S, period) { var R = Std._zeros(S.length); var multiplier = 2.0 / (period + 1); var j = Std._skip(S, period); Std._set(R, 0, j, NaN); if (j < S.length) { R[j] = Std._avg(S, j + 1); for (var i = j + 1; i < S.length; i++) { R[i] = ((S[i] - R[i - 1]) * multiplier) + R[i - 1]; } } return R; }, _cmp: function(arr, start, end, cmpFunc) { var v = arr[start]; for (var i = start; i < end; i++) { v = cmpFunc(arr[i], v); } return v; }, _filt: function(records, n, attr, iv, cmpFunc) { if (records.length < 2) { return NaN; } var v = iv; var pos = n !== 0 ? records.length - Math.min(records.length - 1, n) - 1 : 0; for (var i = records.length - 2; i >= pos; i--) { if (typeof(attr) !== 'undefined') { v = cmpFunc(v, records[i][attr]); } else { v = cmpFunc(v, records[i]); } } return v; }, _ticks: function(records) { if (records.length === 0) { return []; } var ticks = []; if (typeof(records[0].Close) !== 'undefined') { for (var i = 0; i < records.length; i++) { ticks.push(records[i].Close); } } else { ticks = records; } return ticks; }, }; var TA = { Highest: function(records, n, attr) { return Std._filt(records, n, attr, Number.MIN_VALUE, Math.max); }, Lowest: function(records, n, attr) { return Std._filt(records, n, attr, Number.MAX_VALUE, Math.min); }, MA: function(records, period) { period = typeof(period) === 'undefined' ? 9 : period; return Std._sma(Std._ticks(records), period); }, SMA: function(records, period) { period = typeof(period) === 'undefined' ? 9 : period; return Std._sma(Std._ticks(records), period); }, EMA: function(records, period) { period = typeof(period) === 'undefined' ? 9 : period; return Std._ema(Std._ticks(records), period); }, MACD: function(records, fastEMA, slowEMA, signalEMA) { fastEMA = typeof(fastEMA) === 'undefined' ? 12 : fastEMA; slowEMA = typeof(slowEMA) === 'undefined' ? 26 : slowEMA; signalEMA = typeof(signalEMA) === 'undefined' ? 9 : signalEMA; var ticks = Std._ticks(records); var slow = Std._ema(ticks, slowEMA); var fast = Std._ema(ticks, fastEMA); // DIF var dif = Std._diff(fast, slow); // DEA var signal = Std._ema(dif, signalEMA); var histogram = Std._diff(dif, signal); return [dif, signal, histogram]; }, BOLL: function(records, period, multiplier) { period = typeof(period) === 'undefined' ? 20 : period; multiplier = typeof(multiplier) === 'undefined' ? 2 : multiplier; var S = Std._ticks(records); for (var j = period - 1; j < S.length && isNaN(S[j]); j++); var UP = Std._zeros(S.length); var MB = Std._zeros(S.length); var DN = Std._zeros(S.length); Std._set(UP, 0, j, NaN); Std._set(MB, 0, j, NaN); Std._set(DN, 0, j, NaN); var sum = 0; for (var i = j; i < S.length; i++) { if (i == j) { for (var k = 0; k < period; k++) { sum += S[k]; } } else { sum = sum + S[i] - S[i - period]; } var ma = sum / period; var d = 0; for (var k = i + 1 - period; k <= i; k++) { d += (S[k] - ma) * (S[k] - ma); } var stdev = Math.sqrt(d / period); var up = ma + (multiplier * stdev); var dn = ma - (multiplier * stdev); UP[i] = up; MB[i] = ma; DN[i] = dn; } // upper, middle, lower return [UP, MB, DN]; }, KDJ: function(records, n, k, d) { n = typeof(n) === 'undefined' ? 9 : n; k = typeof(k) === 'undefined' ? 3 : k; d = typeof(d) === 'undefined' ? 3 : d; var RSV = Std._zeros(records.length); Std._set(RSV, 0, n - 1, NaN); var K = Std._zeros(records.length); var D = Std._zeros(records.length); var J = Std._zeros(records.length); var hs = Std._zeros(records.length); var ls = Std._zeros(records.length); for (var i = 0; i < records.length; i++) { hs[i] = records[i].High; ls[i] = records[i].Low; } for (var i = 0; i < records.length; i++) { if (i >= (n - 1)) { var c = records[i].Close; var h = Std._cmp(hs, i - (n - 1), i + 1, Math.max); var l = Std._cmp(ls, i - (n - 1), i + 1, Math.min); RSV[i] = 100 * ((c - l) / (h - l)); K[i] = (1 * RSV[i] + (k - 1) * K[i - 1]) / k; D[i] = (1 * K[i] + (d - 1) * D[i - 1]) / d; } else { K[i] = D[i] = 50; RSV[i] = 0; } J[i] = 3 * K[i] - 2 * D[i]; } // remove prefix for (var i = 0; i < n - 1; i++) { K[i] = D[i] = J[i] = NaN; } return [K, D, J]; }, RSI: function(records, period) { period = typeof(period) === 'undefined' ? 14 : period; var i; var n = period; var rsi = Std._zeros(records.length); Std._set(rsi, 0, rsi.length, NaN); if (records.length < n) { return rsi; } var ticks = Std._ticks(records); var deltas = Std._move_diff(ticks); var seed = deltas.slice(0, n); var up = 0; var down = 0; for (i = 0; i < seed.length; i++) { if (seed[i] >= 0) { up += seed[i]; } else { down += seed[i]; } } up /= n; down = -(down /= n); var rs = down != 0 ? up / down : 0; rsi[n] = 100 - 100 / (1 + rs); var delta = 0; var upval = 0; var downval = 0; for (i = n + 1; i < ticks.length; i++) { delta = deltas[i - 1]; if (delta > 0) { upval = delta; downval = 0; } else { upval = 0; downval = -delta; } up = (up * (n - 1) + upval) / n; down = (down * (n - 1) + downval) / n; rs = up / down; rsi[i] = 100 - 100 / (1 + rs); } return rsi; }, OBV: function(records) { if (records.length === 0) { return []; } if (typeof(records[0].Close) === 'undefined') { throw "argument must KLine"; } var R = []; for (var i = 0; i < records.length; i++) { if (i === 0) { R[i] = records[i].Volume; } else if (records[i].Close >= records[i - 1].Close) { R[i] = R[i - 1] + records[i].Volume; } else { R[i] = R[i - 1] - records[i].Volume; } } return R; }, ATR: function(records, period) { if (records.length === 0) { return []; } if (typeof(records[0].Close) === 'undefined') { throw "argument must KLine"; } period = typeof(period) === 'undefined' ? 14 : period; var R = Std._zeros(records.length); var sum = 0; var n = 0; for (var i = 0; i < records.length; i++) { var TR = 0; if (i == 0) { TR = records[i].High - records[i].Low; } else { TR = Math.max(records[i].High - records[i].Low, Math.abs(records[i].High - records[i - 1].Close), Math.abs(records[i - 1].Close - records[i].Low)); } sum += TR; if (i < period) { n = sum / (i + 1); } else { n = (((period - 1) * n) + TR) / period; } R[i] = n; } return R; }, Alligator: function(records, jawLength, teethLength, lipsLength) { jawLength = typeof(jawLength) === 'undefined' ? 13 : jawLength; teethLength = typeof(teethLength) === 'undefined' ? 8 : teethLength; lipsLength = typeof(lipsLength) === 'undefined' ? 5 : lipsLength; var ticks = []; for (var i = 0; i < records.length; i++) { ticks.push((records[i].High + records[i].Low) / 2); } return [ [NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN].concat(Std._smma(ticks, jawLength)), // jaw (blue) [NaN, NaN, NaN, NaN, NaN].concat(Std._smma(ticks, teethLength)), // teeth (red) [NaN, NaN, NaN].concat(Std._smma(ticks, lipsLength)), // lips (green) ]; }, CMF: function(records, periods) { periods = periods || 20; var ret = []; var sumD = 0; var sumV = 0; var arrD = []; var arrV = []; for (var i = 0; i < records.length; i++) { var d = (records[i].High == records[i].Low) ? 0 : (2 * records[i].Close - records[i].Low - records[i].High) / (records[i].High - records[i].Low) * records[i].Volume; arrD.push(d); arrV.push(records[i].Volume); sumD += d; sumV += records[i].Volume; if (i >= periods) { sumD -= arrD.shift(); sumV -= arrV.shift(); } ret.push(sumD / sumV); } return ret; } };
python
import math class Std: @staticmethod def _skip(arr, period): k = 0 for j in xrange(0, len(arr)): if arr[j] is not None: k+=1 if k == period: break return j @staticmethod def _sum(arr, num): s = 0.0 for i in xrange(0, num): if arr[i] is not None: s += arr[i] return s @staticmethod def _avg(arr, num): if len(arr) == 0: return 0 s = 0.0 n = 0 for i in xrange(0, min(len(arr), num)): if arr[i] is not None: s += arr[i] n += 1 if n == 0: return 0 return s / n @staticmethod def _zeros(n): return [0.0] * n @staticmethod def _set(arr, start, end, value): for i in xrange(start, min(len(arr), end)): arr[i] = value @staticmethod def _diff(a, b): d = [None] * len(b) for i in xrange(0, len(b)): if a[i] is not None and b[i] is not None: d[i] = a[i] - b[i] return d @staticmethod def _move_diff(a): d = [None] * (len(a)-1) for i in xrange(1, len(a)): d[i-1] = a[i] - a[i-1] return d @staticmethod def _cmp(arr, start, end, cmpFunc): v = arr[start] for i in xrange(start, end): v = cmpFunc(arr[i], v) return v @staticmethod def _filt(records, n, attr, iv, cmpFunc): if len(records) < 2: return None v = iv pos = 0 if n != 0: pos = len(records) - min(len(records)-1, n) - 1 for i in xrange(len(records)-2, pos-1, -1): if records[i] is not None: if attr is not None: v = cmpFunc(v, records[i][attr]) else: v = cmpFunc(v, records[i]) return v @staticmethod def _ticks(records): if len(records) == 0: return [] if 'Close' not in records[0]: return records ticks = [None] * len(records) for i in xrange(0, len(records)): ticks[i] = records[i]['Close'] return ticks @staticmethod def _sma(S, period): R = Std._zeros(len(S)) j = Std._skip(S, period) Std._set(R, 0, j, None) if j < len(S): s = 0 for i in xrange(j, len(S)): if i == j: s = Std._sum(S, i+1) else: s += S[i] - S[i-period] R[i] = s / period return R @staticmethod def _smma(S, period): R = Std._zeros(len(S)) j = Std._skip(S, period) Std._set(R, 0, j, None) if j < len(S): R[j] = Std._avg(S, j+1) for i in xrange(j+1, len(S)): R[i] = (R[i-1] * (period-1) + S[i]) / period return R @staticmethod def _ema(S, period): R = Std._zeros(len(S)) multiplier = 2.0 / (period + 1) j = Std._skip(S, period) Std._set(R, 0, j, None) if j < len(S): R[j] = Std._avg(S, j+1) for i in xrange(j+1, len(S)): R[i] = ((S[i] - R[i-1] ) * multiplier) + R[i-1] return R class TA: @staticmethod def Highest(records, n, attr=None): return Std._filt(records, n, attr, 5e-324, max) @staticmethod def Lowest(records, n, attr=None): return Std._filt(records, n, attr, 1.7976931348623157e+308, min) @staticmethod def MA(records, period=9): return Std._sma(Std._ticks(records), period) @staticmethod def SMA(records, period=9): return Std._sma(Std._ticks(records), period) @staticmethod def EMA(records, period=9): return Std._ema(Std._ticks(records), period) @staticmethod def MACD(records, fastEMA=12, slowEMA=26, signalEMA=9): ticks = Std._ticks(records) slow = Std._ema(ticks, slowEMA) fast = Std._ema(ticks, fastEMA) # DIF dif = Std._diff(fast, slow) # DEA signal = Std._ema(dif, signalEMA) histogram = Std._diff(dif, signal) return [ dif, signal, histogram] @staticmethod def BOLL(records, period=20, multiplier=2): S = Std._ticks(records) j = period - 1 while j < len(S) and (S[j] is None): j+=1 UP = Std._zeros(len(S)) MB = Std._zeros(len(S)) DN = Std._zeros(len(S)) Std._set(UP, 0, j, None) Std._set(MB, 0, j, None) Std._set(DN, 0, j, None) n = 0.0 for i in xrange(j, len(S)): if i == j: for k in xrange(0, period): n += S[k] else: n = n + S[i] - S[i - period] ma = n / period d = 0 for k in xrange(i+1-period, i+1): d += (S[k] - ma) * (S[k] - ma) stdev = math.sqrt(d / period) up = ma + (multiplier * stdev) dn = ma - (multiplier * stdev) UP[i] = up MB[i] = ma DN[i] = dn return [UP, MB, DN] @staticmethod def KDJ(records, n=9, k=3, d=3): RSV = Std._zeros(len(records)) Std._set(RSV, 0, n - 1, None) K = Std._zeros(len(records)) D = Std._zeros(len(records)) J = Std._zeros(len(records)) hs = Std._zeros(len(records)) ls = Std._zeros(len(records)) for i in xrange(0, len(records)): hs[i] = records[i]['High'] ls[i] = records[i]['Low'] for i in xrange(0, len(records)): if i >= (n - 1): c = records[i]['Close'] h = Std._cmp(hs, i - (n - 1), i + 1, max) l = Std._cmp(ls, i - (n - 1), i + 1, min) RSV[i] = 100 * ((c - l) / (h - l)) K[i] = float(1 * RSV[i] + (k - 1) * K[i - 1]) / k D[i] = float(1 * K[i] + (d - 1) * D[i - 1]) / d else: K[i] = D[i] = 50.0 RSV[i] = 0.0 J[i] = 3 * K[i] - 2 * D[i] # remove prefix for i in xrange(0, n-1): K[i] = D[i] = J[i] = None return [K, D, J] @staticmethod def RSI(records, period=14): n = period rsi = Std._zeros(len(records)) Std._set(rsi, 0, len(rsi), None) if len(records) < n: return rsi ticks = Std._ticks(records) deltas = Std._move_diff(ticks) seed = deltas[:n] up = 0.0 down = 0.0 for i in xrange(0, len(seed)): if seed[i] >= 0: up += seed[i] else: down += seed[i] up /= n down /= n down = -down if down != 0: rs = up / down else: rs = 0 rsi[n] = 100 - 100 / (1 + rs) delta = 0.0 upval = 0.0 downval = 0.0 for i in xrange(n+1, len(ticks)): delta = deltas[i - 1] if delta > 0: upval = delta downval = 0.0 else: upval = 0.0 downval = -delta up = (up * (n - 1) + upval) / n down = (down * (n - 1) + downval) / n rs = up / down rsi[i] = 100 - 100 / (1 + rs) return rsi @staticmethod def OBV(records): if len(records) == 0: return [] if 'Close' not in records[0]: raise "TA.OBV argument must KLine" R = Std._zeros(len(records)) for i in xrange(0, len(records)): if i == 0: R[i] = records[i]['Volume'] elif records[i]['Close'] >= records[i - 1]['Close']: R[i] = R[i - 1] + records[i]['Volume'] else: R[i] = R[i - 1] - records[i]['Volume'] return R @staticmethod def ATR(records, period=14): if len(records) == 0: return [] if 'Close' not in records[0]: raise "TA.ATR argument must KLine" R = Std._zeros(len(records)) m = 0.0 n = 0.0 for i in xrange(0, len(records)): TR = 0 if i == 0: TR = records[i]['High'] - records[i]['Low'] else: TR = max(records[i]['High'] - records[i]['Low'], abs(records[i]['High'] - records[i - 1]['Close']), abs(records[i - 1]['Close'] - records[i]['Low'])) m += TR if i < period: n = m / (i + 1) else: n = (((period - 1) * n) + TR) / period R[i] = n return R @staticmethod def Alligator(records, jawLength=13, teethLength=8, lipsLength=5): ticks = [] for i in xrange(0, len(records)): ticks.append((records[i]['High'] + records[i]['Low']) / 2) return [ [None]*8+Std._smma(ticks, jawLength), # // jaw (blue) [None]*5+Std._smma(ticks, teethLength), # teeth (red) [None]*3+Std._smma(ticks, lipsLength) # lips (green) ] @staticmethod def CMF(records, periods=20): ret = [] sumD = 0.0 sumV = 0.0 arrD = [] arrV = [] for i in xrange(0, len(records)): d = 0.0 if records[i]['High'] != records[i]['Low']: d = (2 * records[i]['Close'] - records[i]['Low'] - records[i]['High']) / (records[i]['High'] - records[i]['Low']) * records[i]['Volume'] arrD.append(d) arrV.append(records[i]['Volume']) sumD += d sumV += records[i]['Volume'] if i >= periods: sumD -= arrD.pop(0) sumV -= arrV.pop(0) ret.append(sumD / sumV) return ret
cpp
double _cmp_min(double a, double b) { return a < b ? a : b; } double _cmp_max(double a, double b) { return a > b ? a : b; } double _cmp_max(double a, double b, double c) { double d = a > b ? a : b; return d > c ? d : c; } class TAHelper { public: array<vector<double>, 3> MACD(Records &records, size_t fastEMA = 12, size_t slowEMA = 26, size_t signalEMA = 9) { vector<double> ticks = records.Close(); vector<double> dif = _diff(_ema(ticks, fastEMA), _ema(ticks, slowEMA)); vector<double> signal = _ema(dif, signalEMA); vector<double> histogram = _diff(dif, signal); return {{ dif, signal, histogram }}; } array<vector<double>, 3> KDJ(Records &records, size_t n = 9, size_t k = 3, size_t d = 3) { size_t length = records.size(); vector<double> RSV(length, 0); _set(RSV, 0, n - 1, NAN); vector<double> K(length, 0); vector<double> D(length, 0); vector<double> J(length, 0); vector<double> hs = records.High(); vector<double> ls = records.Low(); for (size_t i = 0; i < length; i++) { if (i >= size_t(n - 1)) { double c = records[i].Close; double h = _cmp(hs, i - (n - 1), i + 1, _cmp_max); double l = _cmp(ls, i - (n - 1), i + 1, _cmp_min); RSV[i] = h != l ? (100 * ((c - l) / (h - l))) : 100; K[i] = (1 * RSV[i] + (k - 1) * K[i - 1]) / k; D[i] = (1 * K[i] + (d - 1) * D[i - 1]) / d; } else { K[i] = D[i] = 50; RSV[i] = 0; } J[i] = 3 * K[i] - 2 * D[i]; } for (size_t i = 0; i < n - 1; i++) { K[i] = D[i] = J[i] = NAN; } return{{ K, D, J }}; } vector<double> RSI(Records &records, size_t period = 14) { size_t i = 0; size_t n = period; vector<double> rsi(records.size(), 0); _set(rsi, 0, rsi.size(), NAN); if (records.size() < n) { return rsi; } vector<double> ticks = records.Close(); vector<double> deltas = _move_diff(ticks); vector<double> seed(deltas.begin(), deltas.begin() + n); double up = 0.0; double down = 0.0; for (i = 0; i < seed.size(); i++) { if (seed[i] >= 0) { up += seed[i]; } else { down += seed[i]; } } up /= n; down /= n; down = -down; double rs = down != 0 ? up / down : 0; rsi[n] = 100 - 100 / (1 + rs); double delta = 0.0; double upval = 0.0; double downval = 0.0; for (i = n + 1; i < ticks.size(); i++) { delta = deltas[i - 1]; if (delta > 0) { upval = delta; downval = 0; } else { upval = 0; downval = -delta; } up = (up * (n - 1) + upval) / n; down = (down * (n - 1) + downval) / n; rs = up / down; rsi[i] = 100 - 100 / (1 + rs); } return rsi; } vector<double> ATR(Records &records, size_t period = 14) { vector<double> ret; if (records.size() == 0) { return ret; } vector<double> R(records.size(), 0); double sum = 0.0; double n = 0.0; for (size_t i = 0; i < records.size(); i++) { double TR = 0.0; if (i == 0) { TR = records[i].High - records[i].Low; } else { TR = _cmp_max(records[i].High - records[i].Low, abs(records[i].High - records[i - 1].Close), abs(records[i - 1].Close - records[i].Low)); } sum += TR; if (i < period) { n = sum / (i + 1); } else { n = (((period - 1) * n) + TR) / period; } R[i] = n; } return R; } vector<double> OBV(Records &records) { vector<double> R; if (records.size() == 0) { return R; } for (size_t i = 0; i < records.size(); i++) { if (i == 0) { R.push_back(records[i].Volume); } else if (records[i].Close >= records[i - 1].Close) { R.push_back(R[i - 1] + records[i].Volume); } else { R.push_back(R[i - 1] - records[i].Volume); } } return R; } vector<double> MA(Records &records, size_t period = 9) { return _sma(records.Close(), period); } vector<double> EMA(Records &records, size_t period = 9) { return _ema(records.Close(), period); } array<vector<double>, 3> BOLL(Records &records, size_t period = 20, double multiplier = 2) { vector<double> S = records.Close(); size_t j = 0; for (j = period - 1; j < S.size() && isnan(S[j]); j++); vector<double> UP(S.size(), 0); vector<double> MB(S.size(), 0); vector<double> DN(S.size(), 0); _set(UP, 0, j, NAN); _set(MB, 0, j, NAN); _set(DN, 0, j, NAN); double sum = 0; for (size_t i = j; i < S.size(); i++) { if (i == j) { for (size_t k = 0; k < period; k++) { sum += S[k]; } } else { sum = sum + S[i] - S[i - period]; } double ma = sum / period; double d = 0.0; for (size_t k = i + 1 - period; k <= i; k++) { d += (S[k] - ma) * (S[k] - ma); } double stdev = sqrt(d / period); double up = ma + (multiplier * stdev); double dn = ma - (multiplier * stdev); UP[i] = up; MB[i] = ma; DN[i] = dn; } return {{ UP, MB, DN }}; } array<vector<double>, 3> Alligator(Records &records, size_t jawLength = 13, size_t teethLength = 8, size_t lipsLength = 5) { vector<double> ticks; for (size_t i = 0; i < records.size(); i++) { ticks.push_back((records[i].High + records[i].Low) / 2); } vector<double> jaw = _smma(ticks, jawLength); jaw.insert(jaw.begin(), 8, NAN); vector<double> teeth = _smma(ticks, teethLength); teeth.insert(teeth.begin(), 5, NAN); vector<double> lips = _smma(ticks, lipsLength); lips.insert(lips.begin(), 3, NAN); return{{ jaw, teeth, lips }}; } vector<double> CMF(Records &records, size_t periods = 20) { vector<double> ret; double sumD = 0.0; double sumV = 0.0; vector<double> arrD; vector<double> arrV; for (size_t i = 0; i < records.size(); i++) { double d = (records[i].High == records[i].Low) ? 0 : (2 * records[i].Close - records[i].Low - records[i].High) / (records[i].High - records[i].Low) * records[i].Volume; arrD.push_back(d); arrV.push_back(records[i].Volume); sumD += d; sumV += records[i].Volume; if (i >= periods) { sumD -= arrD.front(); arrD.erase(arrD.begin()); sumV -= arrV.front(); arrV.erase(arrV.begin()); } ret.push_back(sumD / sumV); } return ret; } double Highest(vector<double> records, size_t n) { return _filt(records, n, NAN, _cmp_max); } double Lowest(vector<double> records, size_t n) { return _filt(records, n, NAN, _cmp_min); } double _filt(vector<double> records, double n, double iv, double(*pfun) (double a, double b)) { if (records.size() < 2) { return NAN; } double v = iv; double pos = n != 0 ? records.size() - _cmp_min(records.size() - 1, n) - 1 : 0; for (size_t i = records.size() - 2; i >= pos; i--) { v = pfun(v, records[i]); } return v; } vector<double> _smma(vector<double> S, size_t period) { size_t length = S.size(); vector<double> R(length, 0); size_t j = _skip(S, period); _set(R, 0, j, NAN); if (j < length) { R[j] = _avg(S, j + 1); for (size_t i = j + 1; i < length; i++) { R[i] = (R[i - 1] * (period - 1) + S[i]) / period; } } return R; } vector<double> _move_diff(vector<double> a) { vector<double> d; for (size_t i = 1; i < a.size(); i++) { d.push_back(a[i] - a[i - 1]); } return d; } vector<double> _ema(vector<double> S, size_t period) { size_t length = S.size(); vector<double> R(length, 0); double multiplier = 2.0 / (period + 1); size_t j = _skip(S, period); _set(R, 0, j, NAN); if (j < length) { R[j] = _avg(S, j + 1); for (size_t i = j + 1; i < length; i++) { R[i] = (S[i] - R[i - 1]) * multiplier + R[i - 1]; } } return R; } vector<double> _sma(vector<double> S, size_t period) { vector<double> R(S.size(), 0); size_t j = _skip(S, period); _set(R, 0, j, NAN); if (j < S.size()) { double sum = 0; for (size_t i = j; i < S.size(); i++) { if (i == j) { sum = _sum(S, i + 1); } else { if (i < period) { R[i] = NAN; continue; } sum += S[i] - S[i - period]; } R[i] = sum / period; } } return R; } double _sum(vector<double> arr, size_t num) { double sum = 0.0; for (size_t i = 0; i < num; i++) { if (!isnan(arr[i])) { sum += arr[i]; } } return sum; } vector<double> _diff(vector<double> a, vector<double> b) { vector<double> d; for (size_t i = 0; i < b.size(); i++) { if (isnan(a[i]) || isnan(b[i])) { d.push_back(NAN); } else { d.push_back(a[i] - b[i]); } } return d; } double _avg(vector<double> arr, double num) { size_t n = 0; double sum = 0.0; for (size_t i = 0; i < num; i++) { if (!isnan(arr[i])) { sum += arr[i]; n++; } } return sum / n; } void _set(vector<double> &arr, size_t start, size_t end, double value) { size_t e = _cmp_min(arr.size(), end); for (size_t i = start; i < e; i++) { arr[i] = value; } } size_t _skip(vector<double> arr, size_t period) { size_t j = 0; for (size_t k = 0; j < arr.size(); j++) { if (!isnan(arr[j])) { k++; } if (k == period) { break; } } return j; } double _cmp(vector<double> arr, size_t start, size_t end, double(*pfun) (double a, double b)) { double v = arr[start]; for (size_t i = start; i < end; i++) { v = pfun(arr[i], v); } return v; } }; TAHelper TA;
Comment
All comments (0)
No data
No data
  • 1
iPhone Download
Forums
PINE Language
© 2015 - ∞ INVENTOR PTE LTD (SG)