Một thư viện TA được định lượng bởi các nhà phát minh nguồn mở, học cách sử dụng (có phiên bản Javascript/Python/C++)

Tác giả:Không, Tạo: 2016-09-01 16:11:47, Cập nhật: 2020-04-07 16:34:37

Có thể nói rằng các chỉ số được tạo ra như thế nào, và bạn sẽ sử dụng chúng như thế nào? Dưới đây là mã được tự tay viết khi tôi chuyển từ lập trình viên sang ngành tài chính, không có bất kỳ bản sao dán, hy vọng sẽ hữu ích cho những người mới bắt đầu.

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;

Có liên quan

Thêm nữa

ScottliyqTôi đã học được, rất dễ dàng.

ScottliyqTôi đã học được, rất dễ dàng.

pixy3173 666

Chuyện gì thế?Tôi cần nó. Cám ơn.

momoxKhó khăn, cảm thấy py code nhiều hơn js, không khoa học.

Đó là cái tên của mẹ tôi.Nhận thức sâu sắc

KhôngNhiều người viết Python thích giả vờ viết một dòng mã khó hiểu để đại diện cho N dòng mã, nhưng tôi không thích làm điều đó, phong cách của tôi là viết mã dễ hiểu. Không sử dụng ma thuật đen.