Skip to content

Commit

Permalink
stoch rsi
Browse files Browse the repository at this point in the history
  • Loading branch information
Dmitriy Yurov committed Mar 9, 2024
1 parent 7e0d031 commit f964654
Show file tree
Hide file tree
Showing 5 changed files with 270 additions and 3 deletions.
3 changes: 2 additions & 1 deletion index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export { AC } from './src/ac';
export { Move } from './src/move';
export { Wave } from './src/wave';
export { Stochastic } from './src/stochastic';
export { StochasticRSI } from './src/stochastic-rsi';
export { RSI } from './src/rsi';
export { CCI } from './src/cci';
export { ATR } from './src/atr';
Expand All @@ -36,4 +37,4 @@ export { CircularBuffer } from './src/providers/circular-buffer';
export { Sampler } from './src/providers/sampler';
export { VolumeProfile } from './src/volume-profile'; /** BETA UNSTABLE */
export { ChaikinOscillator } from './src/chaikin';
export { OrderBlock } from './src/order-block';
// export { OrderBlock } from './src/order-block';
76 changes: 76 additions & 0 deletions src/stochastic-rsi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { SMA } from './sma';
import { MaxProvider } from './providers/max-value';
import { MinProvider } from './providers/min-value';
import { RSI } from './rsi';

/**
* Developed by Tushar Chande and Stanley Kroll, StochRSI is an oscillator that measures the level of RSI relative
* to its high-low range over a set time period. StochRSI applies the Stochastics formula to RSI values, rather
* than price values, making it an indicator of an indicator. The result is an oscillator that
* fluctuates between 0 and 1.
*/
export class StochasticRSI {
private max: MaxProvider;
private min: MinProvider;
private rsi: RSI;
private sma1: SMA;
private sma2: SMA;

constructor(rsiPeriod = 14, kPeriod = 3, dPeriod = 3, stochPeriod = 14) {
this.rsi = new RSI(rsiPeriod);
this.sma1 = new SMA(kPeriod);
this.sma2 = new SMA(dPeriod);
this.max = new MaxProvider(stochPeriod);
this.min = new MinProvider(stochPeriod);
}

/**
* Get next value for closed candle
* affect all next calculations
*/
nextValue(close: number): { k: number, d: number, stochRsi: number } {
const rsi = this.rsi.nextValue(close);

if (rsi === undefined) {
return;
}

const max = this.max.nextValue(rsi);
const min = this.min.nextValue(rsi);

if (!this.max.filled()) {
return;
}

const stochRsi = ((rsi - min) / (max - min)) * 100;
const k = this.sma1.nextValue(stochRsi);

if (k === undefined) {
return;
}

const d = this.sma2.nextValue(k);

return { k, d, stochRsi };
}

/**
* Get next value for non closed (tick) candle hlc
* does not affect any next calculations
*/
momentValue(close: number): { k: number, d: number, stochRsi: number} {
if (!this.max.filled()) {
return;
}

const rsi = this.rsi.momentValue(close);
const max = this.max.momentValue(rsi);
const min = this.min.momentValue(rsi);

const stochRsi = ((rsi - min) / (max - min)) * 100;
const k = this.sma1.momentValue(stochRsi);
const d = this.sma2.momentValue(k);

return { k, d, stochRsi };
}
}
4 changes: 2 additions & 2 deletions src/stochastic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export class Stochastic {
const max = this.max.nextValue(high);
const min = this.min.nextValue(low);

if (!this.max.filled) {
if (!this.max.filled()) {
return;
}

Expand All @@ -44,7 +44,7 @@ export class Stochastic {
* does not affect any next calculations
*/
momentValue(high: number, low: number, close: number): { k: number; d: number } {
if (!this.max.filled) {
if (!this.max.filled()) {
return;
}

Expand Down
165 changes: 165 additions & 0 deletions tests/stoch-rsi/excel-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
export const ohlc = [
{ o: 1173.0, h: 1189.34998, l: 1162.0, c: 1181.75 },
{ o: 1187.05005, h: 1192.55005, l: 1148.09998, c: 1154.59998 },
{ o: 1156.0, h: 1168.75, l: 1128.44995, c: 1133.19995 },
{ o: 1136.40002, h: 1149.59998, l: 1126.05005, c: 1132.15002 },
{ o: 1136.0, h: 1172.90002, l: 1136.0, c: 1167.40002 },
{ o: 1199.0, h: 1219.80005, l: 1109.0, c: 1122.90002 },
{ o: 1107.44995, h: 1111.0, l: 1085.19995, c: 1099.40002 },
{ o: 1091.44995, h: 1115.55005, l: 1087.19995, c: 1097.59998 },
{ o: 1099.90002, h: 1104.34998, l: 1089.09998, c: 1097.34998 },
{ o: 1099.0, h: 1101.40002, l: 1090.0, c: 1094.90002 },
{ o: 1102.0, h: 1116.0, l: 1100.5, c: 1111.94995 },
{ o: 1113.0, h: 1130.0, l: 1110.59998, c: 1125.94995 },
{ o: 1125.0, h: 1146.84998, l: 1125.0, c: 1138.40002 },
{ o: 1138.40002, h: 1138.40002, l: 1138.40002, c: 1138.40002 },
{ o: 1141.80005, h: 1153.0, l: 1125.09998, c: 1149.90002 },
{ o: 1154.0, h: 1158.5, l: 1143.15002, c: 1152.15002 },
{ o: 1150.0, h: 1155.0, l: 1144.09998, c: 1149.40002 },
{ o: 1144.5, h: 1158.0, l: 1139.0, c: 1153.19995 },
{ o: 1153.09998, h: 1155.90002, l: 1136.05005, c: 1145.05005 },
{ o: 1145.0, h: 1145.0, l: 1130.0, c: 1135.44995 },
{ o: 1130.0, h: 1135.80005, l: 1114.09998, c: 1131.19995 },
{ o: 1133.40002, h: 1150.44995, l: 1133.40002, c: 1145.5 },
{ o: 1150.09998, h: 1157.59998, l: 1132.30005, c: 1136.80005 },
{ o: 1142.94995, h: 1145.0, l: 1119.40002, c: 1122.90002 },
{ o: 1123.0, h: 1143.90002, l: 1122.90002, c: 1138.30005 },
{ o: 1120.0, h: 1140.0, l: 1115.19995, c: 1134.59998 },
{ o: 1127.5, h: 1127.5, l: 1100.09998, c: 1103.84998 },
{ o: 1103.84998, h: 1103.84998, l: 1103.84998, c: 1103.84998 },
{ o: 1103.84998, h: 1103.84998, l: 1103.84998, c: 1103.84998 },
{ o: 1099.94995, h: 1106.0, l: 1090.0, c: 1100.80005 },
{ o: 1083.65002, h: 1094.0, l: 1067.19995, c: 1080.19995 },
{ o: 1080.0, h: 1082.90002, l: 1052.0, c: 1061.5 },
{ o: 1041.0, h: 1045.15002, l: 1011.25, c: 1020.0 },
{ o: 1030.25, h: 1052.0, l: 1023.79999, c: 1047.80005 },
{ o: 1048.0, h: 1063.19995, l: 1042.05005, c: 1052.40002 },
{ o: 1050.0, h: 1062.40002, l: 1038.0, c: 1053.69995 },
{ o: 1050.0, h: 1050.80005, l: 1037.0, c: 1041.15002 },
{ o: 1041.15002, h: 1041.15002, l: 1041.15002, c: 1041.15002 },
{ o: 1040.94995, h: 1059.5, l: 1040.05005, c: 1052.40002 },
{ o: 1058.0, h: 1070.0, l: 1045.0, c: 1066.34998 },
{ o: 1070.0, h: 1098.30005, l: 1056.19995, c: 1087.90002 },
{ o: 1088.0, h: 1095.0, l: 1072.94995, c: 1079.0 },
{ o: 1079.94995, h: 1079.94995, l: 1059.0, c: 1060.69995 },
{ o: 1061.0, h: 1064.80005, l: 1049.05005, c: 1057.75 },
{ o: 1049.0, h: 1064.90002, l: 1040.09998, c: 1049.05005 },
{ o: 1055.30005, h: 1059.0, l: 1040.0, c: 1046.25 },
{ o: 1045.05005, h: 1062.75, l: 1039.30005, c: 1044.40002 },
{ o: 1043.0, h: 1046.94995, l: 1022.54999, c: 1028.19995 },
{ o: 1036.59998, h: 1051.59998, l: 1030.30005, c: 1047.34998 },
{ o: 1054.0, h: 1061.90002, l: 1045.90002, c: 1052.80005 },
{ o: 1049.5, h: 1073.15002, l: 1048.05005, c: 1069.5 },
{ o: 1073.25, h: 1079.09998, l: 1058.80005, c: 1077.55005 },
{ o: 1083.40002, h: 1098.0, l: 1083.40002, c: 1095.84998 },
{ o: 1100.0, h: 1109.80005, l: 1088.0, c: 1107.09998 },
{ o: 1103.40002, h: 1103.40002, l: 1079.44995, c: 1083.15002 },
{ o: 1077.0, h: 1107.40002, l: 1065.94995, c: 1103.44995 },
{ o: 1097.44995, h: 1097.44995, l: 1080.09998, c: 1083.75 },
{ o: 1095.05005, h: 1102.5, l: 1087.05005, c: 1100.84998 },
{ o: 1102.05005, h: 1104.44995, l: 1090.09998, c: 1096.34998 },
{ o: 1096.34998, h: 1096.34998, l: 1096.34998, c: 1096.34998 },
{ o: 1090.0, h: 1110.0, l: 1090.0, c: 1104.75 },
{ o: 1101.25, h: 1110.0, l: 1097.30005, c: 1104.69995 },
{ o: 1101.09998, h: 1106.59998, l: 1083.0, c: 1086.30005 },
{ o: 1090.15002, h: 1109.94995, l: 1087.0, c: 1105.40002 },
{ o: 1100.0, h: 1108.94995, l: 1093.19995, c: 1105.25 },
{ o: 1099.94995, h: 1102.44995, l: 1076.05005, c: 1078.90002 },
{ o: 1085.5, h: 1085.5, l: 1062.25, c: 1074.05005 },
{ o: 1074.65002, h: 1074.65002, l: 1058.90002, c: 1069.34998 },
{ o: 1060.05005, h: 1067.90002, l: 1047.90002, c: 1050.80005 },
{ o: 1061.5, h: 1067.40002, l: 1055.5, c: 1063.30005 },
{ o: 1056.30005, h: 1069.94995, l: 1052.09998, c: 1055.69995 },
{ o: 1062.0, h: 1062.94995, l: 1030.84998, c: 1049.94995 },
{ o: 1057.0, h: 1091.0, l: 1048.09998, c: 1083.40002 },
{ o: 1066.0, h: 1155.0, l: 1054.34998, c: 1133.0 },
{ o: 1148.0, h: 1164.0, l: 1137.55005, c: 1139.90002 },
{ o: 1139.90002, h: 1162.09998, l: 1128.34998, c: 1131.90002 },
{ o: 1135.0, h: 1158.94995, l: 1128.55005, c: 1139.65002 },
{ o: 1134.0, h: 1160.0, l: 1117.0, c: 1121.25 },
{ o: 1135.0, h: 1142.5, l: 1122.0, c: 1137.05005 },
{ o: 1148.09998, h: 1152.5, l: 1131.0, c: 1136.25 },
];

export const rsiValues = [
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
42.50059,
43.1493,
42.51792,
43.74289,
41.69081,
39.34911,
38.32288,
43.64827,
41.31126,
37.82651,
43.51179,
42.50609,
35.22029,
35.22029,
35.22029,
34.48798,
29.95727,
26.54783,
20.87089,
31.44632,
33.04097,
33.51166,
31.22928,
31.22928,
35.7767,
40.98758,
48.00588,
45.59417,
41.02984,
40.32898,
38.25363,
37.58328,
37.12044,
33.25797,
41.06462,
43.1043,
48.93605,
51.51585,
56.85244,
59.78307,
51.72803,
57.01472,
51.15917,
55.43742,
54.09454,
54.09454,
56.38192,
56.3639,
50.0326,
55.60712,
55.55469,
47.14692,
45.77376,
44.42346,
39.47411,
44.00166,
41.94711,
40.40977,
51.53707,
62.66867,
63.91056,
61.36179,
62.90515,
57.076,
60.46395,
60.20482,
];
25 changes: 25 additions & 0 deletions tests/stoch-rsi/stoch-rsi.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ohlc } from './excel-data';
import { StochasticRSI } from '../../src/stochastic-rsi';
import { StochasticRSI as StochasticRSITI } from 'technicalindicators';

describe('StochRSI', () => {
it('Cross sdk validate', () => {
const configTI = { stochasticPeriod: 14, rsiPeriod: 14, kPeriod: 3, dPeriod: 3, values: [] as number[] };
const stochRsi = new StochasticRSI();
const stochRsi2 = new StochasticRSITI(configTI);

ohlc.forEach((tick) => {
configTI.values.push(tick.c);
const local = stochRsi.nextValue(tick.c);
//@ts-expect-error incorrect typings
const cross = stochRsi2.nextValue(tick.c);

if (local?.k && cross?.k) {
//precision issues with technicalindicators setConfig('precision') is not work as expected
expect(Math.abs(local.k - cross.k)).toBeLessThan(0.05);
expect(Math.abs(local.d - cross.d)).toBeLessThan(0.05);
expect(Math.abs(local.stochRsi - cross.stochRSI)).toBeLessThan(0.05);
}
});
});
});

0 comments on commit f964654

Please sign in to comment.