feat(chart): candle build indicator as direction line #1

Open
u1 wants to merge 31 commits from feat/candle-build-indicator into main
Showing only changes of commit 62baa9700e - Show all commits

View File

@@ -6,12 +6,13 @@ import ChartSideToolbar from './ChartSideToolbar';
import ChartToolbar from './ChartToolbar'; import ChartToolbar from './ChartToolbar';
import TradingChart from './TradingChart'; import TradingChart from './TradingChart';
import type { FibAnchor, FibRetracement } from './FibRetracementPrimitive'; import type { FibAnchor, FibRetracement } from './FibRetracementPrimitive';
import type { IChartApi } from 'lightweight-charts'; import { LineStyle, type IChartApi } from 'lightweight-charts';
import type { OverlayLayer } from './ChartPanel.types'; import type { OverlayLayer } from './ChartPanel.types';
type Props = { type Props = {
candles: Candle[]; candles: Candle[];
indicators: ChartIndicators; indicators: ChartIndicators;
dlobQuotes?: { bid: number | null; ask: number | null; mid: number | null } | null;
timeframe: string; timeframe: string;
bucketSeconds: number; bucketSeconds: number;
seriesKey: string; seriesKey: string;
@@ -45,6 +46,7 @@ function isEditableTarget(t: EventTarget | null): boolean {
export default function ChartPanel({ export default function ChartPanel({
candles, candles,
indicators, indicators,
dlobQuotes,
timeframe, timeframe,
bucketSeconds, bucketSeconds,
seriesKey, seriesKey,
@@ -61,6 +63,7 @@ export default function ChartPanel({
const [fib, setFib] = useState<FibRetracement | null>(null); const [fib, setFib] = useState<FibRetracement | null>(null);
const [fibDraft, setFibDraft] = useState<FibRetracement | null>(null); const [fibDraft, setFibDraft] = useState<FibRetracement | null>(null);
const [layers, setLayers] = useState<OverlayLayer[]>([ const [layers, setLayers] = useState<OverlayLayer[]>([
{ id: 'dlob-quotes', name: 'DLOB Quotes', visible: true, locked: false, opacity: 0.9 },
{ id: 'drawings', name: 'Drawings', visible: true, locked: false, opacity: 1 }, { id: 'drawings', name: 'Drawings', visible: true, locked: false, opacity: 1 },
]); ]);
const [layersOpen, setLayersOpen] = useState(false); const [layersOpen, setLayersOpen] = useState(false);
@@ -196,6 +199,37 @@ export default function ChartPanel({
return Math.max(0, Math.min(1, v)); return Math.max(0, Math.min(1, v));
} }
const quotesLayer = useMemo(() => layers.find((l) => l.id === 'dlob-quotes'), [layers]);
const quotesVisible = Boolean(quotesLayer?.visible);
const quotesOpacity = clamp01(quotesLayer?.opacity ?? 1);
const priceLines = useMemo(() => {
if (!quotesVisible) return [];
return [
{
id: 'dlob-bid',
title: 'DLOB Bid',
price: dlobQuotes?.bid ?? null,
color: `rgba(34,197,94,${quotesOpacity})`,
lineStyle: LineStyle.Dotted,
},
{
id: 'dlob-mid',
title: 'DLOB Mid',
price: dlobQuotes?.mid ?? null,
color: `rgba(230,233,239,${quotesOpacity})`,
lineStyle: LineStyle.Dashed,
},
{
id: 'dlob-ask',
title: 'DLOB Ask',
price: dlobQuotes?.ask ?? null,
color: `rgba(239,68,68,${quotesOpacity})`,
lineStyle: LineStyle.Dotted,
},
];
}, [dlobQuotes?.ask, dlobQuotes?.bid, dlobQuotes?.mid, quotesOpacity, quotesVisible]);
function updateLayer(layerId: string, patch: Partial<OverlayLayer>) { function updateLayer(layerId: string, patch: Partial<OverlayLayer>) {
setLayers((prev) => prev.map((l) => (l.id === layerId ? { ...l, ...patch } : l))); setLayers((prev) => prev.map((l) => (l.id === layerId ? { ...l, ...patch } : l)));
} }
@@ -309,6 +343,7 @@ export default function ChartPanel({
showBuild={showBuild} showBuild={showBuild}
bucketSeconds={bucketSeconds} bucketSeconds={bucketSeconds}
seriesKey={seriesKey} seriesKey={seriesKey}
priceLines={priceLines}
fib={fibRenderable} fib={fibRenderable}
fibOpacity={fibEffectiveOpacity} fibOpacity={fibEffectiveOpacity}
fibSelected={fibSelected} fibSelected={fibSelected}