# 开源 发明者量化 的TA库, 学习使用(含Javascript/Python/C++版本)

Author: Zero, Created: 2016-09-01 16:11:47, Updated: 2019-08-01 09:51:18

``````代码就是最好的注释, 不懂指标如何生成的, 怎么敢说自己会用指标.

``````

Javascript

``````var Std = {
_skip: function(arr, period) {
var j = 0;
for (var k = 0; j < arr.length; j++) {
if (!isNaN(arr[j]))
k++;
if (k == period)
break;
}
return j;
},
_sum: function(arr, num) {
var sum = 0.0;
for (var i = 0; i < num; i++) {
if (!isNaN(arr[i])) {
sum += arr[i];
}
}
return sum;
},

_avg: function(arr, num) {
var n = 0;
var sum = 0.0;
for (var i = 0; i < num; i++) {
if (!isNaN(arr[i])) {
sum += arr[i];
n++;
}
}
return sum / n;
},

_zeros: function(len) {
var n = [];
for (var i = 0; i < len; i++) {
n.push(0.0);
}
return n;
},

_set: function(arr, start, end, value) {
var e = Math.min(arr.length, end);
for (var i = start; i < e; i++) {
arr[i] = value;
}
},

_diff: function(a, b) {
var d = [];
for (var i = 0; i < b.length; i++) {
if (isNaN(a[i]) || isNaN(b[i])) {
d.push(NaN);
} else {
d.push(a[i] - b[i]);
}
}
return d;
},
_move_diff: function(a) {
var d = [];
for (var i = 1; i < a.length; i++) {
d.push(a[i] - a[i - 1]);
}
return d;
},
_sma: function(S, period) {
var R = Std._zeros(S.length);
var j = Std._skip(S, period);
Std._set(R, 0, j, NaN);
if (j < S.length) {
var sum = 0;
for (var i = j; i < S.length; i++) {
if (i == j) {
sum = Std._sum(S, i + 1);
} else {
sum += S[i] - S[i - period];
}
R[i] = sum / period;
}
}
return R;
},

_smma: function(S, period) {
var R = Std._zeros(S.length);
var j = Std._skip(S, period);
Std._set(R, 0, j, NaN);
if (j < S.length) {
R[j] = Std._avg(S, j + 1);
for (var i = j + 1; i < S.length; i++) {
R[i] = (R[i - 1] * (period - 1) + S[i]) / period;
}
}
return R;
},
_ema: function(S, period) {
var R = Std._zeros(S.length);
var multiplier = 2.0 / (period + 1);
var j = Std._skip(S, period);
Std._set(R, 0, j, NaN);
if (j < S.length) {
R[j] = Std._avg(S, j + 1);
for (var i = j + 1; i < S.length; i++) {
R[i] = ((S[i] - R[i - 1]) * multiplier) + R[i - 1];
}
}
return R;
},
_cmp: function(arr, start, end, cmpFunc) {
var v = arr[start];
for (var i = start; i < end; i++) {
v = cmpFunc(arr[i], v);
}
return v;
},
_filt: function(records, n, attr, iv, cmpFunc) {
if (records.length < 2) {
return NaN;
}
var v = iv;
var pos = n !== 0 ? records.length - Math.min(records.length - 1, n) - 1 : 0;
for (var i = records.length - 2; i >= pos; i--) {
if (typeof(attr) !== 'undefined') {
v = cmpFunc(v, records[i][attr]);
} else {
v = cmpFunc(v, records[i]);
}
}
return v;
},
_ticks: function(records) {
if (records.length === 0) {
return [];
}
var ticks = [];
if (typeof(records[0].Close) !== 'undefined') {
for (var i = 0; i < records.length; i++) {
ticks.push(records[i].Close);
}
} else {
ticks = records;
}
return ticks;
},
};

var TA = {
Highest: function(records, n, attr) {
return Std._filt(records, n, attr, Number.MIN_VALUE, Math.max);
},
Lowest: function(records, n, attr) {
return Std._filt(records, n, attr, Number.MAX_VALUE, Math.min);
},

MA: function(records, period) {
period = typeof(period) === 'undefined' ? 9 : period;
return Std._sma(Std._ticks(records), period);
},
SMA: function(records, period) {
period = typeof(period) === 'undefined' ? 9 : period;
return Std._sma(Std._ticks(records), period);
},

EMA: function(records, period) {
period = typeof(period) === 'undefined' ? 9 : period;
return Std._ema(Std._ticks(records), period);
},

MACD: function(records, fastEMA, slowEMA, signalEMA) {
fastEMA = typeof(fastEMA) === 'undefined' ? 12 : fastEMA;
slowEMA = typeof(slowEMA) === 'undefined' ? 26 : slowEMA;
signalEMA = typeof(signalEMA) === 'undefined' ? 9 : signalEMA;
var ticks = Std._ticks(records);
var slow = Std._ema(ticks, slowEMA);
var fast = Std._ema(ticks, fastEMA);
// DIF
var dif = Std._diff(fast, slow);
// DEA
var signal = Std._ema(dif, signalEMA);
var histogram = Std._diff(dif, signal);
return [dif, signal, histogram];
},

BOLL: function(records, period, multiplier) {
period = typeof(period) === 'undefined' ? 20 : period;
multiplier = typeof(multiplier) === 'undefined' ? 2 : multiplier;
var S = Std._ticks(records);
for (var j = period - 1; j < S.length && isNaN(S[j]); j++);
var UP = Std._zeros(S.length);
var MB = Std._zeros(S.length);
var DN = Std._zeros(S.length);
Std._set(UP, 0, j, NaN);
Std._set(MB, 0, j, NaN);
Std._set(DN, 0, j, NaN);
var sum = 0;
for (var i = j; i < S.length; i++) {
if (i == j) {
for (var k = 0; k < period; k++) {
sum += S[k];
}
} else {
sum = sum + S[i] - S[i - period];
}
var ma = sum / period;
var d = 0;
for (var k = i + 1 - period; k <= i; k++) {
d += (S[k] - ma) * (S[k] - ma);
}
var stdev = Math.sqrt(d / period);
var up = ma + (multiplier * stdev);
var dn = ma - (multiplier * stdev);
UP[i] = up;
MB[i] = ma;
DN[i] = dn;
}
// upper, middle, lower
return [UP, MB, DN];
},

KDJ: function(records, n, k, d) {
n = typeof(n) === 'undefined' ? 9 : n;
k = typeof(k) === 'undefined' ? 3 : k;
d = typeof(d) === 'undefined' ? 3 : d;

var RSV = Std._zeros(records.length);
Std._set(RSV, 0, n - 1, NaN);
var K = Std._zeros(records.length);
var D = Std._zeros(records.length);
var J = Std._zeros(records.length);

var hs = Std._zeros(records.length);
var ls = Std._zeros(records.length);
for (var i = 0; i < records.length; i++) {
hs[i] = records[i].High;
ls[i] = records[i].Low;
}

for (var i = 0; i < records.length; i++) {
if (i >= (n - 1)) {
var c = records[i].Close;
var h = Std._cmp(hs, i - (n - 1), i + 1, Math.max);
var l = Std._cmp(ls, i - (n - 1), i + 1, Math.min);
RSV[i] = 100 * ((c - l) / (h - l));
K[i] = (1 * RSV[i] + (k - 1) * K[i - 1]) / k;
D[i] = (1 * K[i] + (d - 1) * D[i - 1]) / d;
} else {
K[i] = D[i] = 50;
RSV[i] = 0;
}
J[i] = 3 * K[i] - 2 * D[i];
}
// remove prefix
for (var i = 0; i < n - 1; i++) {
K[i] = D[i] = J[i] = NaN;
}
return [K, D, J];
},

RSI: function(records, period) {
period = typeof(period) === 'undefined' ? 14 : period;
var i;
var n = period;
var rsi = Std._zeros(records.length);
Std._set(rsi, 0, rsi.length, NaN);
if (records.length < n) {
return rsi;
}
var ticks = Std._ticks(records);
var deltas = Std._move_diff(ticks);
var seed = deltas.slice(0, n);
var up = 0;
var down = 0;
for (i = 0; i < seed.length; i++) {
if (seed[i] >= 0) {
up += seed[i];
} else {
down += seed[i];
}
}
up /= n;
down = -(down /= n);
var rs = down != 0 ? up / down : 0;
rsi[n] = 100 - 100 / (1 + rs);
var delta = 0;
var upval = 0;
var downval = 0;
for (i = n + 1; i < ticks.length; i++) {
delta = deltas[i - 1];
if (delta > 0) {
upval = delta;
downval = 0;
} else {
upval = 0;
downval = -delta;
}
up = (up * (n - 1) + upval) / n;
down = (down * (n - 1) + downval) / n;
rs = up / down;
rsi[i] = 100 - 100 / (1 + rs);
}
return rsi;
},
OBV: function(records) {
if (records.length === 0) {
return [];
}
if (typeof(records[0].Close) === 'undefined') {
throw "argument must KLine";
}
var R = [];
for (var i = 0; i < records.length; i++) {
if (i === 0) {
R[i] = records[i].Volume;
} else if (records[i].Close >= records[i - 1].Close) {
R[i] = R[i - 1] + records[i].Volume;
} else {
R[i] = R[i - 1] - records[i].Volume;
}
}
return R;
},
ATR: function(records, period) {
if (records.length === 0) {
return [];
}
if (typeof(records[0].Close) === 'undefined') {
throw "argument must KLine";
}
period = typeof(period) === 'undefined' ? 14 : period;
var R = Std._zeros(records.length);
var sum = 0;
var n = 0;
for (var i = 0; i < records.length; i++) {
var TR = 0;
if (i == 0) {
TR = records[i].High - records[i].Low;
} else {
TR = Math.max(records[i].High - records[i].Low, Math.abs(records[i].High - records[i - 1].Close), Math.abs(records[i - 1].Close - records[i].Low));
}
sum += TR;
if (i < period) {
n = sum / (i + 1);
} else {
n = (((period - 1) * n) + TR) / period;
}
R[i] = n;
}
return R;
},
Alligator: function(records, jawLength, teethLength, lipsLength) {
jawLength = typeof(jawLength) === 'undefined' ? 13 : jawLength;
teethLength = typeof(teethLength) === 'undefined' ? 8 : teethLength;
lipsLength = typeof(lipsLength) === 'undefined' ? 5 : lipsLength;
var ticks = [];
for (var i = 0; i < records.length; i++) {
ticks.push((records[i].High + records[i].Low) / 2);
}
return [
[NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN].concat(Std._smma(ticks, jawLength)), // jaw (blue)
[NaN, NaN, NaN, NaN, NaN].concat(Std._smma(ticks, teethLength)), // teeth (red)
[NaN, NaN, NaN].concat(Std._smma(ticks, lipsLength)), // lips (green)
];
},
CMF: function(records, periods) {
periods = periods || 20;
var ret = [];
var sumD = 0;
var sumV = 0;
var arrD = [];
var arrV = [];
for (var i = 0; i < records.length; i++) {
var d = (records[i].High == records[i].Low) ? 0 : (2 * records[i].Close - records[i].Low - records[i].High) / (records[i].High - records[i].Low) * records[i].Volume;
arrD.push(d);
arrV.push(records[i].Volume);
sumD += d;
sumV += records[i].Volume;
if (i >= periods) {
sumD -= arrD.shift();
sumV -= arrV.shift();
}
ret.push(sumD / sumV);
}
return ret;
}
};
``````

Python

``````import math

class Std:
@staticmethod
def _skip(arr, period):
k = 0
for j in xrange(0, len(arr)):
if arr[j] is not None:
k+=1
if k == period:
break
return j

@staticmethod
def _sum(arr, num):
s = 0.0
for i in xrange(0, num):
if arr[i] is not None:
s += arr[i]
return s

@staticmethod
def _avg(arr, num):
if len(arr) == 0:
return 0
s = 0.0
n = 0
for i in xrange(0, min(len(arr), num)):
if arr[i] is not None:
s += arr[i]
n += 1
if n == 0:
return 0
return s / n

@staticmethod
def _zeros(n):
return [0.0] * n

@staticmethod
def _set(arr, start, end, value):
for i in xrange(start, min(len(arr), end)):
arr[i] = value

@staticmethod
def _diff(a, b):
d = [None] * len(b)
for i in xrange(0, len(b)):
if a[i] is not None and b[i] is not None:
d[i] = a[i] - b[i]
return d

@staticmethod
def _move_diff(a):
d = [None] * (len(a)-1)
for i in xrange(1, len(a)):
d[i-1] = a[i] - a[i-1]
return d

@staticmethod
def _cmp(arr, start, end, cmpFunc):
v = arr[start]
for i in xrange(start, end):
v = cmpFunc(arr[i], v)
return v

@staticmethod
def _filt(records, n, attr, iv, cmpFunc):
if len(records) < 2:
return None
v = iv
pos = 0
if n != 0:
pos = len(records) - min(len(records)-1, n) - 1
for i in xrange(len(records)-2, pos-1, -1):
if records[i] is not None:
if attr is not None:
v = cmpFunc(v, records[i][attr])
else:
v = cmpFunc(v, records[i])
return v

@staticmethod
def _ticks(records):
if len(records) == 0:
return []
if 'Close' not in records[0]:
return records

ticks = [None] * len(records)
for i in xrange(0, len(records)):
ticks[i] = records[i]['Close']
return ticks

@staticmethod
def _sma(S, period):
R = Std._zeros(len(S))
j = Std._skip(S, period)
Std._set(R, 0, j, None)
if j < len(S):
s = 0
for i in xrange(j, len(S)):
if i == j:
s = Std._sum(S, i+1)
else:
s += S[i] - S[i-period]
R[i] = s / period
return R

@staticmethod
def _smma(S, period):
R = Std._zeros(len(S))
j = Std._skip(S, period)
Std._set(R, 0, j, None)
if j < len(S):
R[j] = Std._avg(S, j+1)
for i in xrange(j+1, len(S)):
R[i] = (R[i-1] * (period-1) + S[i]) / period
return R

@staticmethod
def _ema(S, period):
R = Std._zeros(len(S))
multiplier = 2.0 / (period + 1)
j = Std._skip(S, period)
Std._set(R, 0, j, None)
if j < len(S):
R[j] = Std._avg(S, j+1)
for i in xrange(j+1, len(S)):
R[i] = ((S[i] - R[i-1] ) * multiplier) + R[i-1]
return R

class TA:
@staticmethod
def Highest(records, n, attr=None):
return Std._filt(records, n, attr, 5e-324, max)

@staticmethod
def Lowest(records, n, attr=None):
return Std._filt(records, n, attr, 1.7976931348623157e+308, min)

@staticmethod
def MA(records, period=9):
return Std._sma(Std._ticks(records), period)

@staticmethod
def SMA(records, period=9):
return Std._sma(Std._ticks(records), period)

@staticmethod
def EMA(records, period=9):
return Std._ema(Std._ticks(records), period)

@staticmethod
def MACD(records, fastEMA=12, slowEMA=26, signalEMA=9):
ticks = Std._ticks(records)
slow = Std._ema(ticks, slowEMA)
fast = Std._ema(ticks, fastEMA)
# DIF
dif = Std._diff(fast, slow)
# DEA
signal = Std._ema(dif, signalEMA)
histogram = Std._diff(dif, signal)
return [ dif, signal, histogram]

@staticmethod
def BOLL(records, period=20, multiplier=2):
S = Std._ticks(records)
j = period - 1
while j < len(S) and (S[j] is None):
j+=1
UP = Std._zeros(len(S))
MB = Std._zeros(len(S))
DN = Std._zeros(len(S))
Std._set(UP, 0, j, None)
Std._set(MB, 0, j, None)
Std._set(DN, 0, j, None)
n = 0.0
for i in xrange(j, len(S)):
if i == j:
for k in xrange(0, period):
n += S[k]
else:
n = n + S[i] - S[i - period]
ma = n / period
d = 0
for k in xrange(i+1-period, i+1):
d += (S[k] - ma) * (S[k] - ma)
stdev = math.sqrt(d / period)
up = ma + (multiplier * stdev)
dn = ma - (multiplier * stdev)
UP[i] = up
MB[i] = ma
DN[i] = dn
return [UP, MB, DN]

@staticmethod
def KDJ(records, n=9, k=3, d=3):
RSV = Std._zeros(len(records))
Std._set(RSV, 0, n - 1, None)
K = Std._zeros(len(records))
D = Std._zeros(len(records))
J = Std._zeros(len(records))

hs = Std._zeros(len(records))
ls = Std._zeros(len(records))
for i in xrange(0, len(records)):
hs[i] = records[i]['High']
ls[i] = records[i]['Low']

for i in xrange(0, len(records)):
if i >= (n - 1):
c = records[i]['Close']
h = Std._cmp(hs, i - (n - 1), i + 1, max)
l = Std._cmp(ls, i - (n - 1), i + 1, min)
RSV[i] = 100 * ((c - l) / (h - l))
K[i] = float(1 * RSV[i] + (k - 1) * K[i - 1]) / k
D[i] = float(1 * K[i] + (d - 1) * D[i - 1]) / d
else:
K[i] = D[i] = 50.0
RSV[i] = 0.0
J[i] = 3 * K[i] - 2 * D[i]
# remove prefix
for i in xrange(0, n-1):
K[i] = D[i] = J[i] = None
return [K, D, J]

@staticmethod
def RSI(records, period=14):
n = period
rsi = Std._zeros(len(records))
Std._set(rsi, 0, len(rsi), None)
if len(records) < n:
return rsi

ticks = Std._ticks(records)
deltas = Std._move_diff(ticks)
seed = deltas[:n]
up = 0.0
down = 0.0
for i in xrange(0, len(seed)):
if seed[i] >= 0:
up += seed[i]
else:
down += seed[i]
up /= n
down /= n
down = -down
if down != 0:
rs = up / down
else:
rs = 0
rsi[n] = 100 - 100 / (1 + rs)
delta = 0.0
upval = 0.0
downval = 0.0
for i in xrange(n+1, len(ticks)):
delta = deltas[i - 1]
if delta > 0:
upval = delta
downval = 0.0
else:
upval = 0.0
downval = -delta
up = (up * (n - 1) + upval) / n
down = (down * (n - 1) + downval) / n
rs = up / down
rsi[i] = 100 - 100 / (1 + rs)
return rsi
@staticmethod
def OBV(records):
if len(records) == 0:
return []

if 'Close' not in records[0]:
raise "TA.OBV argument must KLine"

R = Std._zeros(len(records))
for i in xrange(0, len(records)):
if i == 0:
R[i] = records[i]['Volume']
elif records[i]['Close'] >= records[i - 1]['Close']:
R[i] = R[i - 1] + records[i]['Volume']
else:
R[i] = R[i - 1] - records[i]['Volume']
return R

@staticmethod
def ATR(records, period=14):
if len(records) == 0:
return []
if 'Close' not in records[0]:
raise "TA.ATR argument must KLine"

R = Std._zeros(len(records))
m = 0.0
n = 0.0
for i in xrange(0, len(records)):
TR = 0
if i == 0:
TR = records[i]['High'] - records[i]['Low']
else:
TR = max(records[i]['High'] - records[i]['Low'], abs(records[i]['High'] - records[i - 1]['Close']), abs(records[i - 1]['Close'] - records[i]['Low']))
m += TR
if i < period:
n = m / (i + 1)
else:
n = (((period - 1) * n) + TR) / period
R[i] = n
return R

@staticmethod
def Alligator(records, jawLength=13, teethLength=8, lipsLength=5):
ticks = []
for i in xrange(0, len(records)):
ticks.append((records[i]['High'] + records[i]['Low']) / 2)
return [
[None]*8+Std._smma(ticks, jawLength), # // jaw (blue)
[None]*5+Std._smma(ticks, teethLength), # teeth (red)
[None]*3+Std._smma(ticks, lipsLength) # lips (green)
]

@staticmethod
def CMF(records, periods=20):
ret = []
sumD = 0.0
sumV = 0.0
arrD = []
arrV = []
for i in xrange(0, len(records)):
d = 0.0
if records[i]['High'] != records[i]['Low']:
d = (2 * records[i]['Close'] - records[i]['Low'] - records[i]['High']) / (records[i]['High'] - records[i]['Low']) * records[i]['Volume']
arrD.append(d)
arrV.append(records[i]['Volume'])
sumD += d
sumV += records[i]['Volume']
if i >= periods:
sumD -= arrD.pop(0)
sumV -= arrV.pop(0)
ret.append(sumD / sumV)
return ret
``````

C++

``````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

pixy3173 666

mapu 科学

momox 辛苦了，感觉py代码比js还多，不科学啊

Zero 好多写python的人喜欢装逼写很晦涩难懂的一行代表N行的代码，我个人不喜欢这么做，我写代码的风格是让人一看就懂. 不用黑魔法. 尽量少用语言的特性, 少用第三方库, 用最通用的最好移植的逻辑语法