Skip to content

Commit

Permalink
fix(series): fixing volume profile series
Browse files Browse the repository at this point in the history
Big introduced when we upgraded d3.

Relates to react-financial#418
  • Loading branch information
markmcdowell committed Feb 26, 2021
1 parent 569209b commit 584dd26
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 6 deletions.
24 changes: 18 additions & 6 deletions packages/series/src/VolumeProfileSeries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ export class VolumeProfileSeries extends React.Component<VolumeProfileSeriesProp
absoluteChange: (d: any) => d.absoluteChange,
bins: 20,
bySession: false,
fill: ({ type }: { type: "up" | "down"; width: number }) => (type === "up" ? "#6BA583" : "#FF0000"),
fill: ({ type }: { type: "up" | "down"; width: number }) =>
type === "up" ? "rgba(38, 166, 154, 0.5)" : "rgba(239, 83, 80, 0.5)",
maxProfileWidthPercent: 50,
orient: "left",
partialStartOK: true,
Expand Down Expand Up @@ -120,9 +121,20 @@ export class VolumeProfileSeries extends React.Component<VolumeProfileSeriesProp
plotData,
} = moreProps;

const { sessionStart, bySession, partialStartOK, partialEndOK } = props;

const { bins, maxProfileWidthPercent, source, volume, absoluteChange, orient, fill, stroke } = props;
const {
sessionStart,
bySession,
partialStartOK,
partialEndOK,
bins,
maxProfileWidthPercent,
source,
volume,
absoluteChange,
orient,
fill,
stroke,
} = props;

const sessionBuilder = accumulatingWindow()
.discardTillStart(!partialStartOK)
Expand All @@ -146,7 +158,7 @@ export class VolumeProfileSeries extends React.Component<VolumeProfileSeriesProp
const rolledup = (data: any[]) => {
const sortFunction = orient === "right" ? descending : ascending;

const sortedData = data.sort(sortFunction);
const sortedData = data.sort((a, b) => sortFunction(a.direction, b.direction));

return rollup(
sortedData,
Expand Down Expand Up @@ -181,7 +193,7 @@ export class VolumeProfileSeries extends React.Component<VolumeProfileSeriesProp
.range([start, end]);

const totalVolumes = volumeInBins.map((volumes) => {
const totalVolume = sum<any>(volumes, (d) => d.value);
const totalVolume = sum<any>(volumes, (d) => d[1]);
const totalVolumeX = xScale(totalVolume);
const widthLocal = base(xScale) - totalVolumeX;
const x = widthLocal < 0 ? totalVolumeX + widthLocal : totalVolumeX;
Expand Down
76 changes: 76 additions & 0 deletions packages/stories/src/indicators/volumeProfile/VolumeProfile.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import * as React from "react";
import { Chart, ChartCanvas } from "@react-financial-charts/core";
import { XAxis, YAxis } from "@react-financial-charts/axes";
import { discontinuousTimeScaleProviderBuilder } from "@react-financial-charts/scales";
import { BarSeries, CandlestickSeries, VolumeProfileSeries } from "@react-financial-charts/series";
import { IOHLCData, withOHLCData } from "../../data";
import { withDeviceRatio, withSize } from "@react-financial-charts/utils";
import { change } from "@react-financial-charts/indicators";

interface ChartProps {
readonly data: IOHLCData[];
readonly height: number;
readonly width: number;
readonly ratio: number;
}

class VolumeProfile extends React.Component<ChartProps> {
private readonly margin = { left: 0, right: 40, top: 0, bottom: 24 };
private readonly xScaleProvider = discontinuousTimeScaleProviderBuilder().inputDateAccessor(
(d: IOHLCData) => d.date,
);

public render() {
const { data: initialData, height, ratio, width } = this.props;

const absoluteChange = change()(initialData);

const { data, xScale, xAccessor, displayXAccessor } = this.xScaleProvider(absoluteChange);

const gridHeight = height - this.margin.top - this.margin.bottom;
const barChartHeight = gridHeight / 4;
const barChartOrigin = (_: number, h: number) => [0, h - barChartHeight];
const max = xAccessor(data[data.length - 1]);
const min = xAccessor(data[Math.max(0, data.length - 100)]);
const xExtents = [min, max];

return (
<ChartCanvas
height={height}
ratio={ratio}
width={width}
margin={this.margin}
data={data}
displayXAccessor={displayXAccessor}
seriesName="Data"
xScale={xScale}
xAccessor={xAccessor}
xExtents={xExtents}
>
<Chart id={1} height={barChartHeight} origin={barChartOrigin} yExtents={this.barChartExtents}>
<BarSeries yAccessor={this.volumeSeries} />
</Chart>
<Chart id={2} yExtents={this.yExtents}>
<CandlestickSeries />
<VolumeProfileSeries />
<XAxis />
<YAxis />
</Chart>
</ChartCanvas>
);
}

private readonly barChartExtents = (data: IOHLCData) => {
return data.volume;
};

private readonly yExtents = (data: IOHLCData) => {
return [data.high, data.low];
};

private readonly volumeSeries = (data: IOHLCData) => {
return data.volume;
};
}

export default withOHLCData()(withSize({ style: { minHeight: 600 } })(withDeviceRatio()(VolumeProfile)));
10 changes: 10 additions & 0 deletions packages/stories/src/indicators/volumeProfile/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import * as React from "react";
import { VolumeProfileSeries } from "../../../../series/src/VolumeProfileSeries";
import VolumeProfile from "./VolumeProfile";

export default {
title: "Visualization/Indicator/Volume Profile",
component: VolumeProfileSeries,
};

export const basic = () => <VolumeProfile />;

0 comments on commit 584dd26

Please sign in to comment.