Skip to content
Web > Charts > Chart Type Walkthroughs > Cartesian

Candlestick (OHLC) Chart of Daily Prices

Known issues

Some chart features have known issues in the current release. See Known issues.

This walkthrough draws one candle per day from its open, high, low, and close, answering "How has a price moved over the last few days?"

Prerequisites

  • Editor mode: click once on the screen, then press Ctrl+d. The AMIDB Shell Tool and the gallery are used as in the quickstart.
  • Data: the example data that stage 1 creates. To use a table of your own instead, see With your own data.

1. Create the example data

The chart reads a table in the Center, so create the table first.

  1. Select Dashboard -> AMIDB Shell Tool....
  2. Run:

    CREATE PUBLIC TABLE ChartDemoDaily (Day UTC, Open Double, High Double, Low Double, Close Double);
    INSERT INTO ChartDemoDaily VALUES
     (parseDate("2026-09-28", "yyyy-MM-dd", "EST5EDT"), 410.2, 415.0, 408.1, 413.5),
     (parseDate("2026-09-29", "yyyy-MM-dd", "EST5EDT"), 413.5, 418.2, 412.0, 417.9),
     (parseDate("2026-09-30", "yyyy-MM-dd", "EST5EDT"), 417.9, 419.5, 411.3, 412.4),
     (parseDate("2026-10-01", "yyyy-MM-dd", "EST5EDT"), 412.4, 414.8, 405.6, 407.0),
     (parseDate("2026-10-02", "yyyy-MM-dd", "EST5EDT"), 407.0, 411.9, 406.2, 410.8),
     (parseDate("2026-10-05", "yyyy-MM-dd", "EST5EDT"), 410.8, 421.3, 410.1, 420.6),
     (parseDate("2026-10-06", "yyyy-MM-dd", "EST5EDT"), 420.6, 424.0, 417.2, 418.1),
     (parseDate("2026-10-07", "yyyy-MM-dd", "EST5EDT"), 418.1, 419.0, 409.9, 411.2),
     (parseDate("2026-10-08", "yyyy-MM-dd", "EST5EDT"), 411.2, 416.7, 410.4, 415.9),
     (parseDate("2026-10-09", "yyyy-MM-dd", "EST5EDT"), 415.9, 422.8, 414.6, 421.7);
    SELECT * FROM ChartDemoDaily;
    
  3. Check that the lower pane shows the 10 rows.

The dates are stored at midnight New York time, the default user time zone, so each one falls on its own day. See Dates on an axis.

2. Create the chart

The gallery creates a datamodel that reads the table, then places the chart.

  1. Select Windows -> New Window, then the edit button on Blank1, then "Create Table / Visualization / Form".
  2. Select "AMI (__AMI)", then "Next >>".
  3. Select the "USER" tile ChartDemoDaily, then "Next >>".
  4. Select "Test (alt+enter)", then "Next >>".
  5. Select the "Cartesian" tab, then the "Candlestick" tile.
  6. Set the fields below the tiles:

    Field Value
    "Time:" Day
    "Open:" Open
    "High:" High
    "Low:" Low
    "Close:" Close
  7. Select "Finish".

  8. Check that the window shows 10 candles, teal where the close is above the open and red where it is below, such as a red candle on Sep 30.

3. Add hover text

The template leaves "Hover Over:" empty, so pointing at a candle shows nothing.

  1. Open Plot -> Edit Layers and select the "Body" layer.
  2. Set "Hover Over:" to:

    formatDate(Day, "EEE yyyy-MM-dd") + "<br>Open: " + formatNumber(Open, "0.00", "") + "<br>High: " + formatNumber(High, "0.00", "") + "<br>Low: " + formatNumber(Low, "0.00", "") + "<br>Close: " + formatNumber(Close, "0.00", "")
    
  3. Select "OK".

  4. Point at a candle, and check that its date and 4 prices show.

See Writing hover text.

4. Stop the first and last candles being cut

The first and last candles are drawn half outside the plot.

  1. Widen the date axis by a day each side, as in Stopping the first and last points being cut off.
  2. Check that every candle is drawn in full.

Result

10 candles over Sep 28 to Oct 9, with no candles on Oct 3 and Oct 4, the weekend.

To check without looking, read the render stats: session.getDevTools().getAllRenderStats() in the AMIDB Shell Tool, with "Run on this web session" selected (see Running a script), or web_debug op=panelRenderStats over MCP. The "Body" and "Wick" layers each report Rows 10 and an empty Problem.

With your own data

If your table holds trades rather than one row per day, shape the rows in the datamodel's query. To try it on the example trades, create ChartDemoTrades as in Using your own data.

  1. Follow stage 2 with the "USER" tile ChartDemoTrades, or the one for your own table, in place of ChartDemoDaily.
  2. When the gallery shows the datamodel's query, replace the query with:

    1
    2
    3
    4
    5
    {
      CREATE TABLE Raw AS EXECUTE SELECT * FROM ChartDemoTrades WHERE ${WHERE} AND Symbol == "MSFT" ORDER BY Time;
      CREATE TABLE ChartDemoDaily AS SELECT (UTC) parseDate(formatDate(Time, "yyyy-MM-dd", "EST5EDT"), "yyyy-MM-dd", "EST5EDT") AS Day, first(Price) AS Open, max(Price) AS High, min(Price) AS Low, last(Price) AS Close FROM Raw GROUP BY formatDate(Time, "yyyy-MM-dd", "EST5EDT") ORDER BY Day;
      DROP TABLE Raw;
    }
    
  3. Select "Test (alt+enter)".

  4. Check that the "Tables" tab shows ChartDemoDaily alone, 3 rows, Oct 7 to Oct 9, the first with an "Open" of 418.1 and a "Close" of 411.2.

Then continue with stage 2: the fields are the same, and any later stages apply as written. To do this over MCP, put the same statements in the onProcess of the datamodel that step 1 of "Over MCP" imports, with USE ds="AMI" before each EXECUTE.

The first statement takes one symbol's trades in time order; the second makes one row per New York day, taking its first, highest, lowest, and last price. The chart then shows 3 candles, the first one red.

Over MCP

An agent builds the same chart from the same table. Connecting an agent is covered in the AI section; the tools are on Building charts over MCP.

  1. Create the datamodel with web_execute op=importDatamodel and this dmJson, then run it once with op=initDatamodelSchema and dmName ChartDemoDaily:

    {"id": "ChartDemoDaily", "queryMode": "startup", "callbacks": [{"name": "onProcess", "amiscript": ["{ CREATE TABLE ChartDemoDaily AS USE ds=\"AMI\" EXECUTE SELECT * FROM ChartDemoDaily; }"]}]}
    
  2. Create the chart:

    {"windowName": "ChartDemoCandle", "templateKey": "tplCandle", "datamodelId": "ChartDemoDaily", "dmTable": "ChartDemoDaily", "title": "ChartDemoCandle", "bindings": "{\"T\": \"Day\", \"O\": \"Open\", \"H\": \"High\", \"L\": \"Low\", \"C\": \"Close\"}"}
    
  3. Run the datamodel again with web_execute op=executeDatamodel, dmName ChartDemoDaily. A chart created over MCP can stay empty until its datamodel runs again, with its axes at 0-100.

  4. Confirm that every layer reports the rows above and an empty Problem: run web_debug op=panelRenderStats.

The call is web_create_chart_from_template.

Removing the example

Remove the chart, then its datamodel, then the table, so that the next walkthrough can reuse the names:

  1. Close the chart's window with its close button, and select "Delete" when asked whether to delete the panel.
  2. Select Dashboard -> Data Modeler..., expand "Datamodels", right-click the chart's datamodel, ChartDemoDaily, and select "Delete Datamodel", then "Yes". If that name was taken when stage 2 ran, the gallery added a number to it, as in ChartDemoDaily1.
  3. Run DROP TABLE ChartDemoDaily; in the AMIDB Shell Tool.
  4. Check that SELECT * FROM ChartDemoDaily; reports Unknown table: ChartDemoDaily.

Over MCP, delete the chart with web_danger op=deletePanel, then the datamodel with op=deleteDatamodel, dmName ChartDemoDaily, and drop the table as in step 3. deleteDatamodel refuses a datamodel that has been committed; delete that one in the Data Modeler as in step 2. See Removing an agent's chart.