<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Bo Nguyen</title>
    <description>The latest articles on DEV Community by Bo Nguyen (@bonv).</description>
    <link>https://dev.to/bonv</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4174533%2Fffe49edb-2c2d-4219-9ed5-922ca449af2c.jpg</url>
      <title>DEV Community: Bo Nguyen</title>
      <link>https://dev.to/bonv</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bonv"/>
    <language>en</language>
    <item>
      <title>Price tags that never cover each other</title>
      <dc:creator>Bo Nguyen</dc:creator>
      <pubDate>Wed, 11 Nov 2026 06:16:42 +0000</pubDate>
      <link>https://dev.to/bonv/price-tags-that-never-cover-each-other-14lk</link>
      <guid>https://dev.to/bonv/price-tags-that-never-cover-each-other-14lk</guid>
      <description>&lt;p&gt;Look at the right edge of a trading chart while a position is open. There is the last price, with the time left in the bar under it. There is the position's entry, its stop and its target. A limit order waits a few ticks away. With quotes on, the bid and the ask sit either side of the last price. The day's high and low have tags, and on a market with daily limits so do the ceiling, the floor and the reference price.&lt;/p&gt;

&lt;p&gt;Layout ON&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3sl6nl0nr73puwhx3es8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3sl6nl0nr73puwhx3es8.png" alt="A long position with its stop and target, a sell limit and the quotes, all within about $70 of the last price. TradeCanvas, the same chart with the layout off and on." width="800" height="183"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Layout OFF&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5slugtme9eqycjmqffun.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5slugtme9eqycjmqffun.png" alt="A long position with its stop and target, a sell limit and the quotes, all within about $70 of the last price. TradeCanvas, the same chart with the layout off and on." width="800" height="183"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most of these are interesting precisely when they are close together: the price is about to touch your order, the stop is a tick under the bid. That is when a naive chart draws them on top of each other and you can read none of them.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why "spread them out" is not enough
&lt;/h2&gt;

&lt;p&gt;The obvious fix is to sort the tags by price and push each one down until it clears the one above. That works for a static picture. On a live chart it fails in a way you notice at once: the last price moves every tick, and a sort-and-push layout moves every tag below it along with it. Your stop's tag jumps up and down while the stop has not moved. The axis becomes the least trustworthy thing on the screen.&lt;/p&gt;

&lt;p&gt;So the layout needs a fixed point. In TradeCanvas that is the last price: its tag always sits on its line, because it is the number you look at most and the one that moves. Everything else is placed relative to it.&lt;/p&gt;
&lt;h2&gt;
  
  
  One anchor, two directions
&lt;/h2&gt;

&lt;p&gt;The tags above the last price are pushed up; the tags below it are pushed down. Each moves only as far as the tag nearer the anchor needs it to, so a tag leaves its own line only when another one would cover it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ceiling&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;still&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;still&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;above&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;            &lt;span class="c1"&gt;// nearest the anchor first&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;below&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ceiling&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ceiling&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;below&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;ceiling&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;above&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="n"&gt;floor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;still&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;still&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;below&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;down&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;above&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;floor&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;above&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;floor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;below&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details matter more than they look:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tags are not all the same height.&lt;/strong&gt; The last price's tag carries the bar countdown under it, so it reaches further down than up. Each tag says how far it reaches above and below its line, and the layout uses those, not one fixed height.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A tag on the anchor's own price goes above it.&lt;/strong&gt; A position opened at the market sits exactly on the last price. Ties have to break the same way every frame, or the two tags swap places as the price flickers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the last price has no tag to anchor to (its tag is hidden, or the price is scrolled off the plot), the tag nearest the middle of the group stays put instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does not fit is left out
&lt;/h2&gt;

&lt;p&gt;Push enough tags down and the last one runs off the bottom of the plot, onto the time axis. Clamping it to the edge would put it back on top of another tag, which is the problem we started with. So a tag pushed past the plot is not drawn at all, while a tag that is still on its own line is always drawn: if your stop is at the bottom edge, you see it.&lt;/p&gt;

&lt;p&gt;The value tags of indicators and drawings go in the gaps between those tags, each gap laid out with a simpler two-pass version: a downward pass that keeps each tag a height below the one above, then an upward pass that brings back what ran off the bottom of the gap. They need no anchor of their own: the tags that matter more are already fixed around them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The other things that sit on a tag
&lt;/h2&gt;

&lt;p&gt;Fixing the axis did not end it. Two bugs found after it shipped, one reported by a developer building on the widget and one by our own browser audit, were about things drawn over the tags on the trading lines, inside the plot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The "+" by the price axis.&lt;/strong&gt; The button that follows the crosshair to place an order or an alert sat at the right edge of the plot, which is exactly where an order's tag ends, with its close button. It covered the close button and took the click meant for it. Now, while the "+" is turned on, the tags end to the left of its strip.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The legend.&lt;/strong&gt; On a phone, the OHLC legend at the top of the plot runs most of the way across. A take-profit near the top of the range had its tag under the legend's text. The legend is drawn on a layer above the tags (it repaints on every pointer move, the tags do not), so the fix is to clip the legend around each tag. The tag stays whole; the part of the legend behind it is left out.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both bugs had the same shape as the axis one: two things that are each correct on their own, placed by code that does not know about the other. The fix each time was to give one of them a rectangle to keep out of.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turning it off
&lt;/h2&gt;

&lt;p&gt;If you place your own tags or want them back on their lines, &lt;code&gt;chart.setAxisLabelsAligned(false)&lt;/code&gt; turns the layout off (orders and positions are then only spread among themselves), and the widget offers it as "No overlapping labels" in the price scale menu. The function that places them, &lt;code&gt;alignAxisTags&lt;/code&gt;, is exported from &lt;code&gt;@tradecanvas/core&lt;/code&gt; if you draw tags of your own and want them to behave the same way.&lt;/p&gt;

</description>
      <category>software</category>
      <category>softwaredevelopment</category>
      <category>tools</category>
    </item>
    <item>
      <title>Three ways to build a trading chart: Lightweight Charts, MetaTrader 5 and Highcharts Stock</title>
      <dc:creator>Bo Nguyen</dc:creator>
      <pubDate>Mon, 02 Nov 2026 14:59:56 +0000</pubDate>
      <link>https://dev.to/bonv/three-ways-to-build-a-trading-chart-lightweight-charts-metatrader-5-and-highcharts-stock-ej6</link>
      <guid>https://dev.to/bonv/three-ways-to-build-a-trading-chart-lightweight-charts-metatrader-5-and-highcharts-stock-ej6</guid>
      <description>&lt;p&gt;Every trading chart solves the same problem: thousands of bars, a few dozen lines computed from them, prices that change several times a second, and a person who needs to read all of it at a glance. The products people use for this made very different choices about where the work happens and who does it. Three of them show the range well.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lightweight Charts&lt;/strong&gt; is a small open-source library for the web. It draws price series, and leaves the trading tools around them to you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MetaTrader 5&lt;/strong&gt; is a trading platform: a desktop terminal, a web terminal and mobile apps, extended with programs written in its own language, MQL5.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Highcharts Stock&lt;/strong&gt; is the financial edition of a general charting suite that draws with SVG, with WebGL brought in for large data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything below comes from their public documentation, linked at the end. We build a chart library ourselves, so we have opinions; we have tried to keep them in the last section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lightweight Charts: a fast core, and a plugin API for the rest
&lt;/h2&gt;

&lt;p&gt;Lightweight Charts is open source under the Apache 2.0 licence, with one condition worth knowing before you ship: its licence requires you to name TradingView as the creator, by showing the notice from its &lt;code&gt;NOTICE&lt;/code&gt; file and a link to tradingview.com on a public page of your site or app. TradingView lists the component at 35 KB.&lt;/p&gt;

&lt;p&gt;What it draws are &lt;strong&gt;series&lt;/strong&gt;: area, bar, baseline, candlestick, histogram and line, each added with &lt;code&gt;chart.addSeries()&lt;/code&gt;. A series cannot change type once added. The current version (5.2) can split a chart into &lt;strong&gt;panes&lt;/strong&gt;, so price and volume can sit in separate areas of one chart, with an API to add panes, move series between them and resize them. A series can also carry &lt;strong&gt;price lines&lt;/strong&gt;, horizontal lines at a price with a title, created in code.&lt;/p&gt;

&lt;p&gt;The docs present indicators and drawing tools as things you build with &lt;strong&gt;plugins&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;em&gt;custom series&lt;/em&gt; is a new way to draw data, with its own data shape and renderer;&lt;/li&gt;
&lt;li&gt;a &lt;em&gt;series primitive&lt;/em&gt; is attached to a series and drawn in its coordinates: a drawing tool, an annotation, an overlay. It can also draw on the price and time scales;&lt;/li&gt;
&lt;li&gt;a &lt;em&gt;pane primitive&lt;/em&gt; belongs to a whole pane, a watermark for example, and cannot draw on the scales.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What it gets right.&lt;/strong&gt; The core is small and stays small, because everything that is not a series lives outside it. The primitive split is a clean way to say where a plugin may draw.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it leaves to you.&lt;/strong&gt; Indicators, drawing tools and their editing, orders you can drag on the chart, a toolbar: if your product needs a trading screen rather than a price chart, that is most of the work. The docs also note it is client-side only and not meant to run on the server.&lt;/p&gt;

&lt;p&gt;TradingView's other web libraries cover that ground. Its comparison page lists &lt;strong&gt;Advanced Charts&lt;/strong&gt; (670 KB, "100+" indicators, more than 80 drawing tools), free with the TradingView logo, and &lt;strong&gt;Trading Platform&lt;/strong&gt; (900 KB, adding trading from the chart, watchlists, multiple chart layouts and the option to disable branding), which connects to a broker's back end for data and order routing. Both are proprietary, and the page says they are provided to companies for public web projects, not for personal use, hobbies, studies or testing. You host them yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  MetaTrader 5: the chart as part of a platform
&lt;/h2&gt;

&lt;p&gt;MetaTrader 5 is not a library you embed in your own product; it is the platform brokers offer their clients, on the desktop, in the browser and on phones. Its desktop help lists 38 technical indicators and 44 graphical objects; the web terminal has a smaller set and places orders from the chart or from market depth. What makes it interesting to anyone building charts is how it lets users extend the chart, because that design has been in use for about fifteen years and is very explicit about computation.&lt;/p&gt;

&lt;p&gt;A custom indicator is an MQL5 program. Its values live in &lt;strong&gt;indicator buffers&lt;/strong&gt;: arrays the program binds with &lt;code&gt;SetIndexBuffer()&lt;/code&gt;. The program does not resize them; the terminal manages their size as bars arrive.&lt;/p&gt;

&lt;p&gt;All of an indicator's work happens in one function, &lt;code&gt;OnCalculate()&lt;/code&gt;, which the terminal calls as prices arrive. It passes the number of bars (&lt;code&gt;rates_total&lt;/code&gt;) and the value the function returned last time (&lt;code&gt;prev_calculated&lt;/code&gt;). On most ticks they are equal, since a tick usually updates the bar that is still forming; when a new bar opens, &lt;code&gt;rates_total&lt;/code&gt; is one more; and when history changes underneath (older bars downloaded, gaps filled), the terminal sets &lt;code&gt;prev_calculated&lt;/code&gt; to zero and the indicator recomputes everything. An indicator that respects this does a tiny amount of work per tick no matter how long the history is.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;OnCalculate()&lt;/code&gt; can also take another indicator's buffer as its input, so indicators stack: a TEMA of a MACD is an ordinary thing to build. The MQL4 reference's comparison page puts MQL5's limits at 512 buffers and 18 drawing styles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it gets right.&lt;/strong&gt; The contract between the platform and the indicator is explicit: who owns the memory, when to compute, how much changed. That is exactly the part web libraries tend to leave vague.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it leaves to you.&lt;/strong&gt; Nothing, if you are a trader. If you are building a product of your own, it is a platform you reach through a broker, not a component you put in your page: you can learn from it, not ship it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Highcharts Stock: SVG first, WebGL when the data gets big
&lt;/h2&gt;

&lt;p&gt;Highcharts describes its library as "based on SVG and some canvas/WebGL". SVG makes every point a real element, easy to style, animate and make accessible. For data that would be too much to draw that way, Highcharts Stock has two answers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data grouping&lt;/strong&gt; replaces a run of points with one grouped point, sized to the chart's pixel width (&lt;code&gt;groupPixelWidth&lt;/code&gt;), and is on by default for line, area, column, candlestick, OHLC and most indicator series. How a group's value is made depends on the series: an average for lines, a sum for columns, open-high-low-close for OHLC, or a function of your own.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Boost module&lt;/strong&gt; goes further: "a stripped down renderer" that draws the data with WebGL, on a canvas inside the chart's SVG, so that very large numbers of points can be drawn quickly. It switches on per series above a threshold (5,000 points by default). The page is clear about the trade: columns become 1 px lines, areas lose their line, dash styles and most marker shapes are not supported, and most interactive features such as animation are off.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Indicators&lt;/strong&gt; are modules. The base module includes SMA; each of the other indicators (the docs list 48, overlays and oscillators) is a separate module loaded after it, and attached to a price series with &lt;code&gt;linkedTo&lt;/code&gt;. &lt;strong&gt;Stock Tools&lt;/strong&gt; is a module that builds a toolbar around the chart for annotations (the drawing tools), indicators and zooming.&lt;/p&gt;

&lt;p&gt;Highcharts is source-available. Its shop sells licences by use: a public website open to users outside your organisation needs a SaaS licence, and a product distributed to or hosted for your customers needs an OEM licence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it gets right.&lt;/strong&gt; Data grouping is the honest answer to "more bars than pixels": draw what can be seen. Modules per indicator keep the download to what a page uses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it leaves to you.&lt;/strong&gt; Order entry: there is no built-in way to place or drag orders on the chart. And because the fast path and the full-featured path are different renderers with different abilities, you choose features with the data size in mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Side by side
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Lightweight Charts&lt;/th&gt;
&lt;th&gt;MetaTrader 5&lt;/th&gt;
&lt;th&gt;Highcharts Stock&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;What it is&lt;/td&gt;
&lt;td&gt;Web library&lt;/td&gt;
&lt;td&gt;Trading platform (desktop, web, mobile)&lt;/td&gt;
&lt;td&gt;Web library&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Licence&lt;/td&gt;
&lt;td&gt;Apache 2.0, attribution shown on a public page&lt;/td&gt;
&lt;td&gt;Offered through brokers&lt;/td&gt;
&lt;td&gt;Source-available, licences by use&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Drawing&lt;/td&gt;
&lt;td&gt;Canvas&lt;/td&gt;
&lt;td&gt;The platform's own&lt;/td&gt;
&lt;td&gt;SVG; WebGL with Boost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Indicators&lt;/td&gt;
&lt;td&gt;Yours, as plugins&lt;/td&gt;
&lt;td&gt;38 built in (desktop), and MQL5 programs&lt;/td&gt;
&lt;td&gt;48 (SMA in the base module, the others one module each)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Drawing tools&lt;/td&gt;
&lt;td&gt;Yours, as plugins&lt;/td&gt;
&lt;td&gt;44 graphical objects (desktop)&lt;/td&gt;
&lt;td&gt;Annotations, with the Stock Tools toolbar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trading on the chart&lt;/td&gt;
&lt;td&gt;Not built in&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Not built in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Large data&lt;/td&gt;
&lt;td&gt;A small core&lt;/td&gt;
&lt;td&gt;Incremental &lt;code&gt;OnCalculate&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Data grouping, Boost&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Ideas worth borrowing
&lt;/h2&gt;

&lt;p&gt;Building TradeCanvas, these are the ideas from this group we think every trading chart should have, whoever writes it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;An explicit contract for computing indicators.&lt;/strong&gt; MetaTrader's &lt;code&gt;prev_calculated&lt;/code&gt; is the right model: on a tick, recompute the last bar, not the history. TradeCanvas indicators can implement &lt;code&gt;update()&lt;/code&gt; for exactly this, and fall back to a full calculation when the bars underneath change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Draw what can be seen.&lt;/strong&gt; A million bars on a 1,000-pixel axis is a thousand columns of pixels; data grouping makes the work scale with the screen, not with the history.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Say where a plugin may draw.&lt;/strong&gt; Series primitives and pane primitives are a good split. A plugin that can draw anywhere eventually draws over something it should not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decide what a faster renderer may drop.&lt;/strong&gt; Boost trades features for speed, openly. We made the other choice for TradeCanvas: our WebGL renderer (still a preview) draws what the GPU can draw the same and hands the rest to Canvas 2D in order, so switching renderer changes speed, not what is drawn. Both are reasonable; the point is to choose and say so.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://tradecanvas.dev/" rel="noopener noreferrer"&gt;Tradecanvas&lt;/a&gt; is a trading chart library for the web under the MIT licence: indicators, drawing tools, orders on the chart and a widget around it, with no logo or credit required on screen. The next posts in this series take the problems of building it one at a time.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Building in Silence: Why Good Code Gets Drowned Out (And the Harsh Reality of Local Tech Culture)</title>
      <dc:creator>Bo Nguyen</dc:creator>
      <pubDate>Tue, 20 Oct 2026 04:05:45 +0000</pubDate>
      <link>https://dev.to/bonv/building-in-silence-why-good-code-gets-drowned-out-and-the-harsh-reality-of-local-tech-culture-4jg6</link>
      <guid>https://dev.to/bonv/building-in-silence-why-good-code-gets-drowned-out-and-the-harsh-reality-of-local-tech-culture-4jg6</guid>
      <description>&lt;p&gt;I’m a Window trading system developer. For the past few years, my daily reality has revolved around low-latency execution engines, orderbook matching, data synchronization, and zero-allocation memory management. &lt;/p&gt;

&lt;p&gt;Like many of you, I jumped on ChatGPT on day one. But the funny paradox? In my day-to-day enterprise and finance work, &lt;strong&gt;LLMs barely helped.&lt;/strong&gt; Enterprise security policies, air-gapped systems, and strict IP protection meant 95% of our codebase had to be written and debugged with raw brainpower. An LLM can't debug a nanosecond race condition in an air-gapped trading system that handles real client money.&lt;/p&gt;

&lt;p&gt;So, in my spare time, I turned that pent-up engineering energy into open-source. Over the years, I've built at least 5 different production-grade projects related to trading and system architecture. Clean code, comprehensive architecture, real problem-solving.&lt;/p&gt;

&lt;p&gt;And that’s when reality hit me in the face.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. The Internet is Flooded, and Quality No Longer Stands Out
&lt;/h3&gt;

&lt;p&gt;A few years ago, if you spent 6 months meticulously building a robust, high-performance tool, developers would genuinely appreciate the craftsmanship. &lt;/p&gt;

&lt;p&gt;Today? The internet is so saturated with thousands of "AI wrapper" apps launched daily that genuine engineering gets lost in the noise. It feels like nobody cares if your architecture is rock-solid. If it doesn't come with flashy marketing or a viral tweet thread, it gets buried under a pile of generic, weekend-hack projects. You put your soul into an engine, and it ends up sitting there with 25 stars on GitHub.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. The Crab Mentality in Local Tech Communities
&lt;/h3&gt;

&lt;p&gt;What hurts worse than general indifference is the toxic reaction from within my local community in Vietnam.&lt;/p&gt;

&lt;p&gt;Instead of fostering a culture of collaboration, there’s an overwhelming &lt;strong&gt;"Crab Mentality" (pulling down anyone trying to crawl out of the bucket)&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The "AI can do that" dismissiveness:&lt;/strong&gt; If you share a deeply optimized module, the immediate knee-jerk reaction from local social feeds is: &lt;em&gt;"Why bother? I could prompt ChatGPT to generate this in 5 minutes."&lt;/em&gt; (Spoiler: No, a prompt cannot handle concurrent lock-free data structures reliably under production load).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Take, close, and rebrand:&lt;/strong&gt; In open source, we expect people to fork, submit PRs, or discuss improvements. Locally, I’ve seen developers pull the code, wipe the git history, close-source it, and use it for their own commercial gain without a single word of attribution or a simple star.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constant gatekeeping &amp;amp; skepticism:&lt;/strong&gt; Rather than looking at what a tool solves, people obsess over finding microscopic flaws or questioning your motives: &lt;em&gt;"Who are you trying to impress?"&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It reached a point where virtually all genuine stars or technical feedback on my repos came from overseas engineers who simply stumbled upon the code and respected the technical merit.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. How Do We Break Out of This?
&lt;/h3&gt;

&lt;p&gt;I’m writing this not to vent, but because I know I can't be the only one feeling this creative exhaustion. When you realize that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pure engineering quality doesn't automatically earn visibility.&lt;/li&gt;
&lt;li&gt;Your immediate local peers prefer to tear your work down rather than lift it up.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;How do you keep the drive to build?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I’d love to hear from developers across the world:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Is this crab mentality specific to emerging tech scenes, or do you experience the same cynicism in your country?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;In an era of relentless AI-generated noise, how do you get genuine technical work noticed without becoming a full-time marketer?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;For those who broke out of toxic local bubbles: What was your turning point?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s talk in the comments below.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>ai</category>
      <category>programming</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I built my own zero-dependency financial chart engine with Canvas</title>
      <dc:creator>Bo Nguyen</dc:creator>
      <pubDate>Sat, 10 Oct 2026 04:21:05 +0000</pubDate>
      <link>https://dev.to/bonv/i-built-my-own-zero-dependency-financial-chart-engine-with-canvas-2i9</link>
      <guid>https://dev.to/bonv/i-built-my-own-zero-dependency-financial-chart-engine-with-canvas-2i9</guid>
      <description>&lt;p&gt;If you've ever tried building a trading dashboard or a crypto app, you know the drill:&lt;/p&gt;

&lt;p&gt;TradingView Charting Library: Powerful, but the advanced version requires strict approval, business verification, and mandatory branding.&lt;/p&gt;

&lt;p&gt;Enterprise solutions (like AG Charts / SciChart): Insanely expensive for solo devs and indie hackers just bootstrapping an MVP.&lt;/p&gt;

&lt;p&gt;Lightweight options: Often lack smooth interactions, custom indicator layers, or flexible drawing capabilities.&lt;/p&gt;

&lt;p&gt;A while ago, I ran into this exact wall while working on my own trading setup. I didn’t want to pay enterprise licensing just to render candles, nor did I want to bloat my bundle with massive dependencies.&lt;/p&gt;

&lt;p&gt;So, I decided to go down the rabbit hole and build TradeCanvas from scratch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkhhvyve5treen5kcb4z9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkhhvyve5treen5kcb4z9.png" alt="Candlesticks to Renko, 111 indicators, 69 drawing tools, live exchange feeds and orders on the chart. Drawn with Canvas 2D or WebGL, with zero dependencies" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
What I set out to solve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Pure Canvas rendering: Direct control over pixel projection, rendering loop, and double-buffering without DOM thrashing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;60 FPS smoothness: Viewport culling so panning across thousands of historical ticks doesn't choke the browser.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Clean separation of layers: Separated the background grid, main candles, crosshair overlay, and indicator pipelines so rendering one doesn't force a full repaint of everything.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Zero vendor lock-in: A clean, standalone library designed for developers who just want full control of their charting stack.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's still in active development, but the core engine, multi-timeframe candle rendering, dynamic price/time scaling, and interactions are working.&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
  </channel>
</rss>
