Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature #15138, added test and algorithm for OBV.
- Loading branch information
1 parent
d93b70d
commit acb0796
Showing
9 changed files
with
406 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
resources: | ||
- https://code.jquery.com/qunit/qunit-2.0.1.js | ||
- https://code.jquery.com/qunit/qunit-2.0.1.css | ||
js_wrap: b | ||
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<script src="https://code.highcharts.com/stock/highstock.js"></script> | ||
<script src="https://code.highcharts.com/stock/indicators/indicators.js"></script> | ||
<script src="https://code.highcharts.com/stock/indicators/obv.js"></script> | ||
|
||
<div id="qunit"></div> | ||
<div id="qunit-fixture"></div> | ||
|
||
|
||
<div id="container" style="width: 600px; margin: 0 auto;"></div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
QUnit.test('Test RSI calculations on data updates.', function (assert) { | ||
const chart = Highcharts.stockChart('container', { | ||
yAxis: [{ | ||
height: '60%' | ||
}, { | ||
height: '20%', | ||
top: '60%' | ||
}, { | ||
height: '20%', | ||
top: '80%' | ||
}], | ||
series: [{ | ||
id: 'main', | ||
data: [ | ||
[1552311000000, 10], | ||
[1552397400000, 10.15], | ||
[1552483800000, 10.17], | ||
[1552570200000, 10.13], | ||
[1552656600000, 10.11], | ||
[1552915800000, 10.15], | ||
[1553002200000, 10.20], | ||
[1553088600000, 10.20], | ||
[1553175000000, 10.22] | ||
] | ||
}, { | ||
type: 'column', | ||
id: 'volume', | ||
yAxis: 1, | ||
data: [ | ||
[1552311000000, 25200], | ||
[1552397400000, 30000], | ||
[1552483800000, 25600], | ||
[1552570200000, 32000], | ||
[1552656600000, 23000], | ||
[1552915800000, 40000], | ||
[1553002200000, 36000], | ||
[1553088600000, 20500], | ||
[1553175000000, 23000] | ||
] | ||
}, { | ||
volumeSeriesID: 'volume', | ||
type: 'obv', | ||
linkedTo: 'main', | ||
yAxis: 2 | ||
}] | ||
}); | ||
|
||
assert.strictEqual( | ||
chart.series[0].points.length, | ||
chart.series[1].points.length, | ||
'OBV should have the same amount of points as the main series.' | ||
); | ||
|
||
chart.series[0].addPoint([1553261400000, 10.21], false); | ||
chart.series[1].addPoint([1553261400000, 27500]); | ||
|
||
assert.strictEqual( | ||
chart.series[0].points.length, | ||
chart.series[1].points.length, | ||
'OBV should have the same amount of points as the main series after adding point.' | ||
); | ||
|
||
assert.deepEqual( | ||
chart.series[2].yData, | ||
[ | ||
0, | ||
30000, | ||
55600, | ||
23600, | ||
600, | ||
40600, | ||
76600, | ||
76600, | ||
99600, | ||
72100 | ||
], | ||
'Correct values' | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,227 @@ | ||
/* * | ||
* | ||
* License: www.highcharts.com/license | ||
* | ||
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! | ||
* | ||
* */ | ||
|
||
'use strict'; | ||
|
||
import type { | ||
OBVOptions, | ||
OBVParamsOptions | ||
} from './OBVOptions'; | ||
import type OBVPoint from './OBVPoint'; | ||
import type IndicatorValuesObject from '../IndicatorValuesObject'; | ||
import type LineSeries from '../../../Series/Line/LineSeries'; | ||
import SeriesRegistry from '../../../Core/Series/SeriesRegistry.js'; | ||
import Series from '../../../Core/Series/Series'; | ||
const { | ||
seriesTypes: { | ||
sma: SMAIndicator | ||
} | ||
} = SeriesRegistry; | ||
import U from '../../../Core/Utilities.js'; | ||
const { | ||
isNumber, | ||
merge | ||
} = U; | ||
|
||
/** | ||
* The OBV series type. | ||
* | ||
* @private | ||
* @class | ||
* @name Highcharts.seriesTypes.obv | ||
* | ||
* @augments Highcharts.Series | ||
*/ | ||
class OBVIndicator extends SMAIndicator { | ||
/** | ||
* On-Balance Volume (OBV) technical indicator. This series | ||
* requires the `linkedTo` option to be set and should be loaded after | ||
* the `stock/indicators/indicators.js` file. | ||
* | ||
* @sample stock/indicators/obv | ||
* OBV indicator | ||
* | ||
* @extends plotOptions.sma | ||
* @since next | ||
* @product highstock | ||
* @requires stock/indicators/indicators | ||
* @requires stock/indicators/obv | ||
* @optionparent plotOptions.obv | ||
*/ | ||
public static defaultOptions: OBVOptions = merge(SMAIndicator.defaultOptions, { | ||
params: { | ||
volumeSeriesID: 'volume' | ||
} | ||
} as OBVOptions); | ||
|
||
/* * | ||
* | ||
* Properties | ||
* | ||
* */ | ||
|
||
public data: Array<OBVPoint> = void 0 as any; | ||
public points: Array<OBVPoint> = void 0 as any; | ||
public options: OBVOptions = void 0 as any; | ||
|
||
/* * | ||
* | ||
* Functions | ||
* | ||
* */ | ||
|
||
public getCloseValues( | ||
yVal: Array<number> | Array<Array<number>> | ||
): Array<number> { | ||
const index: number = 3; // take close value | ||
let values: Array<number>; | ||
|
||
if (isNumber(yVal[0])) { | ||
// For line series. | ||
values = yVal as Array<number>; | ||
} else { | ||
// For OHLC series. | ||
values = (yVal as Array<Array<number>>).map((value: Array<number>): number => value[index]); | ||
} | ||
|
||
return values; | ||
} | ||
|
||
public getTrend( | ||
curentClose: number, | ||
previousClose: number | ||
): number { | ||
let trend: number = void 0 as any; | ||
|
||
if (curentClose > previousClose) { | ||
trend = 1; // up | ||
} | ||
if (curentClose === previousClose) { | ||
trend = 0; // constant | ||
} | ||
if (curentClose < previousClose) { | ||
trend = -1; // down | ||
} | ||
|
||
return trend; | ||
} | ||
|
||
public getValues<TLinkedSeries extends LineSeries>( | ||
series: TLinkedSeries, | ||
params: OBVParamsOptions | ||
): (IndicatorValuesObject<TLinkedSeries>|undefined) { | ||
const volumeSeries = series.chart.get(params.volumeSeriesID as string), | ||
xVal: Array<number> = (series.xData as any), | ||
yVal: Array<number> | Array<Array<number>> = (series.yData as any), | ||
OBV: Array<Array<number>> = [], | ||
xData: Array<number> = [], | ||
yData: Array<number> = []; | ||
|
||
let OBVPoint: Array<number> = [], | ||
i: number = 0, | ||
previousOBV: number = 0, | ||
curentOBV: number = 0, | ||
previousClose: number = 0, | ||
curentClose: number = 0, | ||
volume: Array<number>, | ||
closeValues: Array<number>, | ||
trend: number; | ||
|
||
// Checks if volume series exists. | ||
if (volumeSeries) { | ||
closeValues = this.getCloseValues(yVal); | ||
volume = ((volumeSeries as Series).yData as any); | ||
|
||
for (i; i < closeValues.length; i++) { | ||
// Add first point and qet close value. | ||
if (i === 0) { | ||
OBVPoint = [xVal[i], previousOBV]; | ||
previousClose = closeValues[i]; | ||
} else { | ||
curentClose = closeValues[i]; | ||
trend = this.getTrend(curentClose, previousClose); | ||
|
||
if (trend === 1) { | ||
curentOBV = previousOBV + volume[i]; | ||
} | ||
if (trend === 0) { | ||
curentOBV = previousOBV; | ||
} | ||
if (trend === -1) { | ||
curentOBV = previousOBV - volume[i]; | ||
} | ||
|
||
// Add point. | ||
OBVPoint = [xVal[i], curentOBV]; | ||
|
||
// Asing currend as previous for next iteration | ||
previousOBV = curentOBV; | ||
previousClose = curentClose; | ||
} | ||
|
||
OBV.push(OBVPoint); | ||
xData.push(xVal[i]); | ||
yData.push(OBVPoint[1]); | ||
} | ||
} else { | ||
return; | ||
} | ||
|
||
return { | ||
values: OBV, | ||
xData: xData, | ||
yData: yData | ||
} as IndicatorValuesObject<TLinkedSeries>; | ||
} | ||
} | ||
|
||
/* * | ||
* | ||
* Prototype Properties | ||
* | ||
* */ | ||
|
||
interface OBVIndicator { | ||
pointClass: typeof OBVPoint; | ||
} | ||
|
||
/* * | ||
* | ||
* Registry | ||
* | ||
* */ | ||
declare module '../../../Core/Series/SeriesType' { | ||
interface SeriesTypeRegistry { | ||
obv: typeof OBVIndicator; | ||
} | ||
} | ||
|
||
SeriesRegistry.registerSeriesType('obv', OBVIndicator); | ||
|
||
/* * | ||
* | ||
* Default Export | ||
* | ||
* */ | ||
|
||
export default OBVIndicator; | ||
|
||
/** | ||
* A `OBV` series. If the [type](#series.obv.type) option is not | ||
* specified, it is inherited from [chart.type](#chart.type). | ||
* | ||
* @extends series,plotOptions.obv | ||
* @since next | ||
* @product highstock | ||
* @excluding dataParser, dataURL | ||
* @requires stock/indicators/indicators | ||
* @requires stock/indicators/obv | ||
* @apioption series.obv | ||
*/ | ||
|
||
''; // to include the above in the js output |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
/* * | ||
* | ||
* License: www.highcharts.com/license | ||
* | ||
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! | ||
* | ||
* */ | ||
|
||
/* * | ||
* | ||
* Imports | ||
* | ||
* */ | ||
|
||
import type { | ||
SMAOptions, | ||
SMAParamsOptions | ||
} from '../SMA/SMAOptions'; | ||
|
||
/* * | ||
* | ||
* Declarations | ||
* | ||
* */ | ||
|
||
export interface OBVOptions extends SMAOptions { | ||
params?: OBVParamsOptions; | ||
} | ||
|
||
export interface OBVParamsOptions extends SMAParamsOptions { | ||
// for inheritance | ||
volumeSeriesID?: string; | ||
} | ||
|
||
export default OBVOptions; |
Oops, something went wrong.