#region Setup using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using ChartForgeX.Core; using ChartForgeX.Primitives; using ChartForgeX.Rendering; using ChartForgeX.Themes; using ChartForgeX.Topology; using ChartForgeX.Typography; using ChartForgeX.VisualArtifacts; using ChartForgeX.VisualBlocks; var mode = VisualThemeMode.Dark; var theme = VisualTheme.Graphite(); var model = OhlcRecipe.Create("dashed", mode); var context = new VisualRenderContext( new VisualLayoutOptions(new VisualSize(800, 440)), theme, mode, new VisualFrame("Daily market price ranges", "Direction-specific dash patterns and phase preserve the source prices", showLegend: null, showSurface: false)); var prepared = model.Prepare(context); File.WriteAllText("visual.svg", prepared.ToSvg()); File.WriteAllBytes("visual.png", prepared.ToPng()); File.WriteAllText("visual.html", prepared.ToArtifact("example", VisualArtifactKind.Chart).ToHtmlPage()); #endregion /// Builds daily opening, high, low and closing prices as tick marks. public static class OhlcRecipe { /// Creates the selected OHLC example with optional rising and falling stroke styles. public static Chart Create(string variant = "wide", VisualThemeMode mode = VisualThemeMode.Light) { if (variant is not ("wide" or "compact" or "sparse" or "options" or "compact-options" or "dashed" or "compact-dashed")) throw new ArgumentOutOfRangeException(nameof(variant)); var chart = Chart.Create(); if (variant is "options" or "compact-options" or "dashed" or "compact-dashed") { var prices = ChartSeries.CreateOhlc(new ChartSeriesId("daily-prices"), "Daily prices", new[] { new ChartCandlestick(1, 44, 58, 38, 53), new ChartCandlestick(2, 53, 60, 42, 45), new ChartCandlestick(3, 46, 55, 41, 46), new ChartCandlestick(4, 47, 47, 47, 47), new ChartCandlestick(5, 47, 63, 44, 58) }); prices.ConfigureFinancial(financial => { financial.Rising.Stroke = ChartColor.FromHex("#2A967B"); financial.Rising.StrokeWidth = 2.4; financial.Falling.Stroke = ChartColor.FromHex("#DB825B"); financial.Falling.StrokeWidth = 2.8; financial.Falling.StrokeOpacity = .85; }).WithPointColor(4, "#729BB7"); if (variant is "dashed" or "compact-dashed") prices.ConfigureFinancial(financial => { financial.Rising.DashPattern = new[] { 7d, 5d, 2d }; financial.Rising.DashOffset = -3; financial.Falling.DashPattern = new[] { 4d, 4d }; financial.Falling.DashOffset = 2; }); chart.WithXLabels("Mon", "Tue", "Wed", "Thu", "Fri").WithYAxis("Price") .WithPointLegend().WithDataLabels(false).AddSeries(prices); } else if (variant == "sparse") { var values = Enumerable.Range(1, 2).Select(index => new ChartCandlestick(index, 30 + index * 3, 44 + index * 3, 20 + index * 3, index % 2 == 0 ? 26 + index * 3 : 38 + index * 3)); chart.WithXLabels("Mon", "Tue", "Wed", "Thu", "Fri", "Sat").AddSeries(ChartSeries.CreateOhlc(new ChartSeriesId("market-price"), "Market price", values)); } else { // Daily open, high, low and close for every October 2026 trading session. var sessions = new[] { "Oct 1", "Oct 2", "Oct 5", "Oct 6", "Oct 7", "Oct 8", "Oct 9", "Oct 12", "Oct 13", "Oct 14", "Oct 15", "Oct 16", "Oct 19", "Oct 20", "Oct 21", "Oct 22", "Oct 23", "Oct 26", "Oct 27", "Oct 28", "Oct 29", "Oct 30" }; var quotes = new[] { (112.6, 112.9, 111.1, 112.4), (112.7, 113.7, 109.5, 111.5), (111.3, 112.0, 109.9, 110.6), (110.8, 111.5, 108.6, 110.4), (110.8, 112.7, 109.4, 112.2), (112.0, 112.8, 110.6, 112.2), (112.3, 114.2, 111.3, 113.5), (113.9, 114.5, 112.6, 113.6), (114.1, 114.9, 112.8, 114.2), (114.5, 115.8, 112.5, 114.0), (113.5, 117.8, 112.5, 115.8), (116.3, 118.2, 114.7, 116.6), (116.0, 118.5, 115.3, 117.2), (117.1, 119.1, 116.2, 116.7), (116.3, 116.6, 115.7, 116.0), (116.5, 119.1, 114.6, 118.6), (118.1, 120.6, 117.5, 119.7), (119.2, 120.6, 118.1, 120.2), (119.8, 121.0, 119.0, 119.8), (119.8, 122.7, 119.5, 121.2), (121.7, 123.0, 121.4, 122.0), (122.3, 124.6, 121.1, 124.3) }; var prices = ChartSeries.CreateOhlc(new ChartSeriesId("market-price"), "Market price", quotes.Select((quote, index) => new ChartCandlestick(index + 1, quote.Item1, quote.Item2, quote.Item3, quote.Item4))); // A five-session average of the close smooths the daily movement. var average = ChartSeries.CreateLine(new ChartSeriesId("five-session-average"), "Five-session average", quotes.Select((quote, index) => new ChartPoint(index + 1, Math.Round(quotes.Skip(Math.Max(0, index - 4)).Take(Math.Min(5, index + 1)).Average(item => item.Item4), 2)))); chart.WithXLabels(sessions).WithYAxis("Price (USD)").WithYAxisBounds(106, 126).AddSeries(prices).AddSeries(average); } return chart; } }