Librería de TA cuantificada por inventores de código abierto, aprender a usar (con versiones de Javascript/Python/C++)

El autor:No hay nada, Creado: 2016-09-01 16:11:47, Actualizado: 2020-04-07 16:34:37

El código es el mejor comentario, no entiendo cómo se generan los indicadores, cómo me atrevo a decir que voy a usarlos. El siguiente código fue hecho a mano cuando pasé de ser un programador a trabajar en el sector financiero, sin copias y pegadas, y espero que sea útil para los principiantes.

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;

Relacionados

Más.

- ¿ Qué?Aprendí, es muy fácil.

- ¿ Qué?Aprendí, es muy fácil.

Pixy3173 666

¿Qué es eso?Es justo lo que necesitaba. Gracias.

el momoxEs muy difícil, parece que hay más código py que js, no es científico.

Mi abuela lo llamaba así.En el fondo.

No hay nadaMuchos de los escritores de Python prefieren escribir una línea de código difícil de entender que representa N líneas, pero yo personalmente no me gusta hacerlo, mi estilo de código es fácil de ver. No uso magia negra.