The resource loading... loading...

Quantified TA library by open source inventors, learn to use (includes Javascript/Python/C++ version)

Author: Zero, Created: 2016-09-01 16:11:47, Updated: 2020-04-07 16:34:37

The code is the best commentary, without understanding how the indicator is generated, how dare you say you will use it. The following code was hand-crafted by me when I was a programmer and moved into the financial industry, without any copy-pasting, hopefully useful for beginners.

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;
    }
};
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
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;

Related

More

scottliyqI've learned a lot, and it's very convenient.

scottliyqI've learned a lot, and it's very convenient.

pixy3173 666

I'm going to go.I just needed it. Thank you.

momoxIt's hard, it feels like there's more py code than there is js, it's not scientific.

This is what my grandmother called it.Deeply sympathetic

ZeroMany Python writers like to pretend to write a line of code that represents N lines of code that are difficult to understand, and I personally don't like to do that. My style of writing code is to make it easy for people to understand. No black magic.