| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- import 'dart:math';
- import '../entity/index.dart';
- class DataUtil {
- static calculate(List<KLineEntity> dataList,
- [List<int> maDayList = const [5, 10, 20], int n = 20, k = 2]) {
- /// calculate main state
- calcMA(dataList, maDayList);
- calcBOLL(dataList, n, k);
- calcSAR(dataList);
- /// calculate secondary state
- calcVolumeMA(dataList);
- calcKDJ(dataList);
- calcMACD(dataList);
- calcRSI(dataList);
- calcWR(dataList);
- calcCCI(dataList);
- }
- static calcMA(List<KLineEntity> dataList, List<int> maDayList) {
- List<double> ma = List<double>.filled(maDayList.length, 0);
- if (dataList.isNotEmpty) {
- for (int i = 0; i < dataList.length; i++) {
- KLineEntity entity = dataList[i];
- final closePrice = entity.close;
- entity.maValueList = List<double>.filled(maDayList.length, 0);
- for (int j = 0; j < maDayList.length; j++) {
- ma[j] += closePrice;
- if (i == maDayList[j] - 1) {
- entity.maValueList?[j] = ma[j] / maDayList[j];
- } else if (i >= maDayList[j]) {
- ma[j] -= dataList[i - maDayList[j]].close;
- entity.maValueList?[j] = ma[j] / maDayList[j];
- }
- }
- }
- }
- }
- static void calcSAR(List<KLineEntity> dataList) {
- const List<double> params = [2, 2, 20]; //calcParams default
- final startAf = params[0] / 100;
- final step = params[1] / 100;
- final maxAf = params[2] / 100;
- // Acceleration factor
- double af = startAf;
- // Extreme point
- double ep = -100;
- // Determine trend direction — false: downtrend
- bool isIncreasing = false;
- double sar = 0;
- for (int i = 0; i < dataList.length; ++i) {
- // the previous period SAR
- final preSar = sar;
- final high = dataList[i].high;
- final low = dataList[i].low;
- if (isIncreasing) {
- // Uptrend
- if (ep == -100 || ep < high) {
- // Reinitialize parameters
- ep = high;
- af = min(af + step, maxAf);
- }
- sar = preSar + af * (ep - preSar);
- final lowMin = min(dataList[max(1, i) - 1].low, low);
- if (sar > dataList[i].low) {
- sar = ep;
- // Reinitialize parameters
- af = startAf;
- ep = -100;
- isIncreasing = !isIncreasing;
- } else if (sar > lowMin) {
- sar = lowMin;
- }
- } else {
- if (ep == -100 || ep > low) {
- // Reinitialize parameters
- ep = low;
- af = min(af + step, maxAf);
- }
- sar = preSar + af * (ep - preSar);
- final highMax = max(dataList[max(1, i) - 1].high, high);
- if (sar < dataList[i].high) {
- sar = ep;
- // Reinitialize parameters
- af = 0;
- ep = -100;
- isIncreasing = !isIncreasing;
- } else if (sar < highMax) {
- sar = highMax;
- }
- }
- dataList[i].sar = sar;
- }
- }
- static void calcBOLL(List<KLineEntity> dataList, int n, int k) {
- _calcBOLLMA(n, dataList);
- for (int i = 0; i < dataList.length; i++) {
- KLineEntity entity = dataList[i];
- if (i >= n) {
- double md = 0;
- for (int j = i - n + 1; j <= i; j++) {
- double c = dataList[j].close;
- double m = entity.BOLLMA!;
- double value = c - m;
- md += value * value;
- }
- md = md / (n - 1);
- md = sqrt(md);
- entity.mb = entity.BOLLMA!;
- entity.up = entity.mb! + k * md;
- entity.dn = entity.mb! - k * md;
- }
- }
- }
- static void _calcBOLLMA(int day, List<KLineEntity> dataList) {
- double ma = 0;
- for (int i = 0; i < dataList.length; i++) {
- KLineEntity entity = dataList[i];
- ma += entity.close;
- if (i == day - 1) {
- entity.BOLLMA = ma / day;
- } else if (i >= day) {
- ma -= dataList[i - day].close;
- entity.BOLLMA = ma / day;
- } else {
- entity.BOLLMA = null;
- }
- }
- }
- static void calcMACD(List<KLineEntity> dataList) {
- double ema12 = 0;
- double ema26 = 0;
- double dif = 0;
- double dea = 0;
- double macd = 0;
- for (int i = 0; i < dataList.length; i++) {
- KLineEntity entity = dataList[i];
- final closePrice = entity.close;
- if (i == 0) {
- ema12 = closePrice;
- ema26 = closePrice;
- } else {
- // EMA(12) = 前一日EMA(12) X 11/13 + 今日收盘价 X 2/13
- ema12 = ema12 * 11 / 13 + closePrice * 2 / 13;
- // EMA(26) = 前一日EMA(26) X 25/27 + 今日收盘价 X 2/27
- ema26 = ema26 * 25 / 27 + closePrice * 2 / 27;
- }
- // DIF = EMA(12) - EMA(26) 。
- // 今日DEA = (前一日DEA X 8/10 + 今日DIF X 2/10)
- // 用(DIF-DEA)*2即为MACD柱状图。
- dif = ema12 - ema26;
- dea = dea * 8 / 10 + dif * 2 / 10;
- macd = (dif - dea) * 2;
- entity.dif = dif;
- entity.dea = dea;
- entity.macd = macd;
- }
- }
- static void calcVolumeMA(List<KLineEntity> dataList) {
- double volumeMa5 = 0;
- double volumeMa10 = 0;
- for (int i = 0; i < dataList.length; i++) {
- KLineEntity entry = dataList[i];
- volumeMa5 += entry.vol;
- volumeMa10 += entry.vol;
- if (i == 4) {
- entry.MA5Volume = (volumeMa5 / 5);
- } else if (i > 4) {
- volumeMa5 -= dataList[i - 5].vol;
- entry.MA5Volume = volumeMa5 / 5;
- } else {
- entry.MA5Volume = 0;
- }
- if (i == 9) {
- entry.MA10Volume = volumeMa10 / 10;
- } else if (i > 9) {
- volumeMa10 -= dataList[i - 10].vol;
- entry.MA10Volume = volumeMa10 / 10;
- } else {
- entry.MA10Volume = 0;
- }
- }
- }
- static void calcRSI(List<KLineEntity> dataList) {
- double? rsi;
- double rsiABSEma = 0;
- double rsiMaxEma = 0;
- for (int i = 0; i < dataList.length; i++) {
- KLineEntity entity = dataList[i];
- final double closePrice = entity.close;
- if (i == 0) {
- rsi = 0;
- rsiABSEma = 0;
- rsiMaxEma = 0;
- } else {
- double rMax = max(0, closePrice - dataList[i - 1].close.toDouble());
- double rAbs = (closePrice - dataList[i - 1].close.toDouble()).abs();
- rsiMaxEma = (rMax + (14 - 1) * rsiMaxEma) / 14;
- rsiABSEma = (rAbs + (14 - 1) * rsiABSEma) / 14;
- rsi = (rsiMaxEma / rsiABSEma) * 100;
- }
- if (i < 13) rsi = null;
- if (rsi != null && rsi.isNaN) rsi = null;
- entity.rsi = rsi;
- }
- }
- static void calcKDJ(List<KLineEntity> dataList) {
- var preK = 50.0;
- var preD = 50.0;
- final tmp = dataList.first;
- tmp.k = preK;
- tmp.d = preD;
- tmp.j = 50.0;
- for (int i = 1; i < dataList.length; i++) {
- final entity = dataList[i];
- final n = max(0, i - 8);
- var low = entity.low;
- var high = entity.high;
- for (int j = n; j < i; j++) {
- final t = dataList[j];
- if (t.low < low) {
- low = t.low;
- }
- if (t.high > high) {
- high = t.high;
- }
- }
- final cur = entity.close;
- var rsv = (cur - low) * 100.0 / (high - low);
- rsv = rsv.isNaN ? 0 : rsv;
- final k = (2 * preK + rsv) / 3.0;
- final d = (2 * preD + k) / 3.0;
- final j = 3 * k - 2 * d;
- preK = k;
- preD = d;
- entity.k = k;
- entity.d = d;
- entity.j = j;
- }
- }
- static void calcWR(List<KLineEntity> dataList) {
- double r;
- for (int i = 0; i < dataList.length; i++) {
- KLineEntity entity = dataList[i];
- int startIndex = i - 14;
- if (startIndex < 0) {
- startIndex = 0;
- }
- double max14 = double.minPositive;
- double min14 = double.maxFinite;
- for (int index = startIndex; index <= i; index++) {
- max14 = max(max14, dataList[index].high);
- min14 = min(min14, dataList[index].low);
- }
- if (i < 13) {
- entity.r = -10;
- } else {
- r = -100 * (max14 - dataList[i].close) / (max14 - min14);
- if (r.isNaN) {
- entity.r = null;
- } else {
- entity.r = r;
- }
- }
- }
- }
- static void calcCCI(List<KLineEntity> dataList) {
- final size = dataList.length;
- final count = 14;
- for (int i = 0; i < size; i++) {
- final kline = dataList[i];
- final tp = (kline.high + kline.low + kline.close) / 3;
- final start = max(0, i - count + 1);
- var amount = 0.0;
- var len = 0;
- for (int n = start; n <= i; n++) {
- amount += (dataList[n].high + dataList[n].low + dataList[n].close) / 3;
- len++;
- }
- final ma = amount / len;
- amount = 0.0;
- for (int n = start; n <= i; n++) {
- amount +=
- (ma - (dataList[n].high + dataList[n].low + dataList[n].close) / 3)
- .abs();
- }
- final md = amount / len;
- kline.cci = ((tp - ma) / 0.015 / md);
- if (kline.cci!.isNaN) {
- kline.cci = 0.0;
- }
- }
- }
- }
|