UNPKG

@uzh-bf/react-option-charts

Version:
124 lines 6.91 kB
var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; import * as React from "react"; import { XAxis, YAxis, } from "@react-financial-charts/axes"; import { CurrentCoordinate, MouseCoordinateX, } from "@react-financial-charts/coordinates"; import { ChartCanvas, Chart, GenericChartComponent, } from "@react-financial-charts/core"; import { LineSeries, } from "@react-financial-charts/series"; import { SingleValueTooltip, } from '@react-financial-charts/tooltip'; import { withSize, withDeviceRatio, } from "@react-financial-charts/utils"; import { blackScholes } from "black-scholes"; import { scaleLinear } from "d3-scale"; import { MouseCoordinateYAccessor } from "./MouseCoordinateYAccessor.js"; import { format, formatUSD, rangeMinSize } from "./utils.js"; ; ; const calcLegValue = (o, underlyingPrice, r) => blackScholes(underlyingPrice, o.k, o.t, o.v, r, o.callPut) || 0; const calcValue = (optionLegs, underlyingPrice, r) => { let total = 0; const optionLegValues = optionLegs.reduce((acc, o, i) => { const legValue = calcLegValue(o, underlyingPrice, r) * (o.quantity || 1); total += legValue; acc.push(legValue); return acc; }, []); return { total, optionLegValues, }; }; const OptionPayoffChart = (props) => { const { s, r, strategies, children, onCurrentValueChanged } = props, chartCanvasProps = __rest(props, ["s", "r", "strategies", "children", "onCurrentValueChanged"]); const [lastX, setLastX] = React.useState(s); const strategyByName = strategies.reduce((acc, strategy) => { const strat = Object.assign(Object.assign({}, strategy), { value: calcValue(strategy.optionLegs, s, r) }); acc[strat.name] = strat; if (strat.showPayoff) { const minT = Math.min(...strat.optionLegs.map(o => o.t)); const title = format(strat.payoffTitle || "{0} payoff", strat.name); acc[title] = Object.assign(Object.assign({}, strat), { color: strat.payoffColor || strat.color, optionLegs: strat.optionLegs.map(o => { return Object.assign(Object.assign({}, o), { t: o.t - minT }); }) }); } return acc; }, {}); const strategyNames = Object.keys(strategyByName); const strategyValues = strategyNames.reduce((acc, strategyName) => { acc[strategyName] = strategyByName[strategyName].value; return acc; }, {}); React.useEffect(() => { onCurrentValueChanged && onCurrentValueChanged(s, strategyValues, strategyValues); }, [s, r, strategies]); const allLegs = strategies.flatMap(strat => strat.optionLegs); const v = Math.max(...allLegs.map(o => o.v)); const keyXs = allLegs.map(o => o.k); if (s) keyXs.push(s); let minX = Math.floor(Math.min(...keyXs) * Math.max(0, 1 - v)); let maxX = Math.ceil(Math.max(...keyXs) * Math.min(2, 1 + v)); if (maxX - minX == 1) { minX = Math.max(0, minX - 1); maxX += 1; } const data = rangeMinSize(maxX - minX, minX).map(x => { return strategyNames.reduce((acc, strategyName) => { var _a; const strat = strategyByName[strategyName]; acc[strategyName] = calcValue(strat.optionLegs, x, r).total - (((_a = strat.value) === null || _a === void 0 ? void 0 : _a.total) || 0); return acc; }, { x }); }); const xExtents = [minX, maxX]; const xScale = scaleLinear([0, maxX - minX], [minX, maxX]); const xAccessor = (data) => data.x; const yExtents = (data) => { const minY = Math.min(...strategyNames.map(strategyName => data[strategyName])); const maxY = Math.max(...strategyNames.map(strategyName => data[strategyName])); return [minY - Math.abs(minY * .2), maxY + Math.abs(maxY * .2)]; }; const yAccessor = (strategyName) => (data) => data[strategyName]; const series = strategyNames.map(strategyName => (React.createElement(LineSeries, { key: `series-${strategyName}`, strokeStyle: strategyByName[strategyName].color, yAccessor: yAccessor(strategyName) }))); const coords = strategyNames.map(strategyName => (React.createElement(CurrentCoordinate, { key: `coords-${strategyName}`, fillStyle: strategyByName[strategyName].color, strokeStyle: strategyByName[strategyName].color, yAccessor: yAccessor(strategyName) }))); const edges = strategyNames.map(strategyName => (React.createElement(MouseCoordinateYAccessor, { key: `edges-${strategyName}`, at: "right", orient: "right", displayFormat: formatUSD, yAccessor: yAccessor(strategyName) }))); const tooltips = strategyNames.map((strategyName, i) => (React.createElement(SingleValueTooltip, { key: `tooltips-${strategyName}`, yAccessor: yAccessor(strategyName), yLabel: strategyName, yDisplayFormat: formatUSD, labelFill: strategyByName[strategyName].color, origin: [8, (i + 1) * 16] }))); const currentValueChanged = (ctx, { currentItem }) => { var _a; const _b = !!currentItem && currentItem, { x } = _b, strategies = __rest(_b, ["x"]); if (x === lastX) return; else setLastX(x); const currentValues = (_a = Object.keys(strategies)) === null || _a === void 0 ? void 0 : _a.reduce((acc, strategyName) => { if (strategyByName[strategyName]) { acc[strategyName] = calcValue(strategyByName[strategyName].optionLegs, x, r); } return acc; }, {}); onCurrentValueChanged && onCurrentValueChanged(x, strategyValues, currentValues); }; return (React.createElement(ChartCanvas, Object.assign({}, chartCanvasProps, { data: data, margin: { left: 0, right: 50, top: 0, bottom: 30 }, xScale: xScale, xAccessor: xAccessor, xExtents: xExtents }), React.createElement(Chart, { id: 1, yExtents: yExtents }, React.createElement(XAxis, null), React.createElement(YAxis, { ticks: 5 }), React.createElement(MouseCoordinateX, { at: "bottom", orient: "bottom", displayFormat: formatUSD }), onCurrentValueChanged && React.createElement(GenericChartComponent, { clip: false, canvasDraw: currentValueChanged, drawOn: ["mousemove"] }), series, coords, edges, tooltips, children))); }; export default withSize({ style: { minHeight: 300 } })(withDeviceRatio()( // @ts-ignore OptionPayoffChart)); //# sourceMappingURL=OptionPayoffChart.js.map