[{"data":1,"prerenderedAt":2197},["ShallowReactive",2],{"doc:\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fcreate-a-stock-chart-with-openpyxl":3,"surround:\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fcreate-a-stock-chart-with-openpyxl":2163,"ancestors:\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fcreate-a-stock-chart-with-openpyxl":2172,"children:\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fcreate-a-stock-chart-with-openpyxl":2177,"related:\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fcreate-a-stock-chart-with-openpyxl":2178},{"id":4,"title":5,"body":6,"dateModified":2129,"datePublished":2129,"description":2130,"extension":2131,"faq":2132,"keyword":2141,"kind":2142,"meta":2143,"navigation":410,"path":2152,"seo":2153,"slug":2156,"stem":2157,"topics":2158,"type":2161,"__hash__":2162},"docs\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fcreate-a-stock-chart-with-openpyxl\u002Findex.md","Create a Stock Chart with openpyxl",{"type":7,"value":8,"toc":2116},"minimark",[9,19,24,53,63,375,379,382,528,531,535,538,922,941,945,948,1082,1102,1194,1198,1201,1461,1479,1483,1486,1567,1570,1648,1652,1655,1969,1972,1976,2017,2021,2040,2044,2050,2063,2073,2079,2083,2112],[10,11,12,13,18],"p",{},"A stock chart — Excel's name for the open-high-low-close (OHLC) chart, drawn as candlesticks — shows each day's range and direction at a glance: a vertical line from the low to the high, and a box between the opening and closing price, coloured by whether the price rose or fell. It is not only for share prices: daily min\u002Fmax\u002Ffirst\u002Flast readings of anything — energy prices, sensor values, queue lengths — fit the same shape. openpyxl can build the chart natively, but Excel's stock chart type is strict about how the data is arranged and needs a few properties the defaults leave off. This page, part of ",[14,15,17],"a",{"href":16},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002F","Creating Charts in Excel with openpyxl",", goes through them.",[20,21,23],"h2",{"id":22},"prerequisites","Prerequisites",[25,26,31],"pre",{"className":27,"code":28,"language":29,"meta":30,"style":30},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl pandas\n","bash","",[32,33,34],"code",{"__ignoreMap":30},[35,36,39,43,47,50],"span",{"class":37,"line":38},"line",1,[35,40,42],{"class":41},"sMTad","pip",[35,44,46],{"class":45},"srMev"," install",[35,48,49],{"class":45}," openpyxl",[35,51,52],{"class":45}," pandas\n",[10,54,55,58,59,62],{},[32,56,57],{},"prices.xlsx"," has twenty trading days of prices for one instrument — date, open, high, low, close and volume — on a sheet called ",[32,60,61],{},"Prices",". The dates are business days only: there are no rows for weekends.",[64,65,73,74,73,78,73,82,73,90,73,100,73,105,73,116,73,122,73,128,73,131,73,137,73,141,73,145,73,149,73,153,73,157,73,161,73,165,73,169,73,173,73,177,73,181,73,186,73,188,73,192,73,196,73,200,73,202,73,205,73,207,73,210,73,212,73,215,73,217,73,220,73,223,73,227,73,229,73,233,73,235,73,238,73,240,73,243,73,245,73,248,73,250,73,253,73,255,73,258,73,261,73,265,73,267,73,270,73,272,73,275,73,277,73,280,73,282,73,285,73,287,73,290,73,292,73,295,73,298,73,302,73,304,73,307,73,309,73,312,73,314,73,317,73,319,73,322,73,324,73,327,73,329,73,332,73,338,73,343,73,352,73,360,73,366,73,371],"svg",{"viewBox":66,"role":67,"ariaLabelledBy":68,"xmlns":71,"style":72},"25 0 710 198","img",[69,70],"st-data-t","st-data-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:710px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[75,76,77],"title",{"id":69},"The column order a stock chart needs",[79,80,81],"desc",{"id":70},"A worksheet with Date, Open, High, Low, Close and Volume columns. The four price columns must be in exactly the order Open, High, Low, Close for Excel's open-high-low-close chart.",[83,84],"rect",{"x":85,"y":86,"width":87,"height":88,"fill":89},"25","0","710","198","#ffffff",[83,91],{"x":92,"y":93,"width":94,"height":95,"rx":96,"fill":97,"stroke":98,"style":99},"41.4","16.0","435.4","30.0","8","#e7ebef","var(--line,#cdd5e6)","stroke-width:1.5px",[83,101],{"x":92,"y":102,"width":94,"height":103,"rx":86,"fill":97,"stroke":98,"style":104},"38.0","8.0","stroke-width:0px",[106,107,109],"g",{"transform":108},"translate(51.4,23.0) scale(0.667)",[110,111],"path",{"d":112,"fill":113,"stroke":114,"style":115},"M6 3h9l4 4v14H6z M15 3v4h4 M9.5 11.5l4.5 6 M14 11.5l-4.5 6","none","var(--teal-ink,#0b6157)","stroke-width:2.70px;stroke-linecap:round;stroke-linejoin:round",[117,118,57],"text",{"x":119,"y":120,"style":121},"73.4","36.0","font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:start",[83,123],{"x":92,"y":124,"width":125,"height":126,"rx":86,"fill":97,"stroke":98,"style":127},"46.0","32.0","24.0","stroke-width:1px",[83,129],{"x":119,"y":124,"width":130,"height":126,"rx":86,"fill":97,"stroke":98,"style":127},"67.3",[117,132,136],{"x":133,"y":134,"style":135},"107.0","63.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[83,138],{"x":139,"y":124,"width":140,"height":126,"rx":86,"fill":97,"stroke":98,"style":127},"140.7","67.6",[117,142,144],{"x":143,"y":134,"style":135},"174.5","B",[83,146],{"x":147,"y":124,"width":148,"height":126,"rx":86,"fill":97,"stroke":98,"style":127},"208.3","67.1",[117,150,152],{"x":151,"y":134,"style":135},"241.8","C",[83,154],{"x":155,"y":124,"width":156,"height":126,"rx":86,"fill":97,"stroke":98,"style":127},"275.4","63.7",[117,158,160],{"x":159,"y":134,"style":135},"307.2","D",[83,162],{"x":163,"y":124,"width":164,"height":126,"rx":86,"fill":97,"stroke":98,"style":127},"339.1","66.3",[117,166,168],{"x":167,"y":134,"style":135},"372.2","E",[83,170],{"x":171,"y":124,"width":172,"height":126,"rx":86,"fill":97,"stroke":98,"style":127},"405.4","71.4",[117,174,176],{"x":175,"y":134,"style":135},"441.1","F",[83,178],{"x":92,"y":179,"width":125,"height":180,"rx":86,"fill":97,"stroke":98,"style":127},"70.0","28.0",[117,182,185],{"x":183,"y":184,"style":135},"57.4","89.0","1",[83,187],{"x":119,"y":179,"width":130,"height":180,"rx":86,"fill":89,"stroke":98,"style":127},[117,189,191],{"x":133,"y":184,"style":190},"font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Date",[83,193],{"x":139,"y":179,"width":140,"height":180,"rx":86,"fill":194,"stroke":195,"style":99},"#f0f4ff","var(--brand,#5b5cf0)",[117,197,199],{"x":143,"y":184,"style":198},"font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Open",[83,201],{"x":147,"y":179,"width":148,"height":180,"rx":86,"fill":194,"stroke":195,"style":99},[117,203,204],{"x":151,"y":184,"style":198},"High",[83,206],{"x":155,"y":179,"width":156,"height":180,"rx":86,"fill":194,"stroke":195,"style":99},[117,208,209],{"x":159,"y":184,"style":198},"Low",[83,211],{"x":163,"y":179,"width":164,"height":180,"rx":86,"fill":194,"stroke":195,"style":99},[117,213,214],{"x":167,"y":184,"style":198},"Close",[83,216],{"x":171,"y":179,"width":172,"height":180,"rx":86,"fill":89,"stroke":98,"style":127},[117,218,219],{"x":175,"y":184,"style":190},"Volume",[83,221],{"x":92,"y":222,"width":125,"height":180,"rx":86,"fill":97,"stroke":98,"style":127},"98.0",[117,224,226],{"x":183,"y":225,"style":135},"117.0","2",[83,228],{"x":119,"y":222,"width":130,"height":180,"rx":86,"fill":89,"stroke":98,"style":127},[117,230,232],{"x":133,"y":225,"style":231},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","01 Sep",[83,234],{"x":139,"y":222,"width":140,"height":180,"rx":86,"fill":89,"stroke":98,"style":127},[117,236,237],{"x":143,"y":225,"style":231},"100.00",[83,239],{"x":147,"y":222,"width":148,"height":180,"rx":86,"fill":89,"stroke":98,"style":127},[117,241,242],{"x":151,"y":225,"style":231},"100.02",[83,244],{"x":155,"y":222,"width":156,"height":180,"rx":86,"fill":89,"stroke":98,"style":127},[117,246,247],{"x":159,"y":225,"style":231},"98.44",[83,249],{"x":163,"y":222,"width":164,"height":180,"rx":86,"fill":89,"stroke":98,"style":127},[117,251,252],{"x":167,"y":225,"style":231},"99.68",[83,254],{"x":171,"y":222,"width":172,"height":180,"rx":86,"fill":89,"stroke":98,"style":127},[117,256,257],{"x":175,"y":225,"style":231},"19326",[83,259],{"x":92,"y":260,"width":125,"height":180,"rx":86,"fill":97,"stroke":98,"style":127},"126.0",[117,262,264],{"x":183,"y":263,"style":135},"145.0","3",[83,266],{"x":119,"y":260,"width":130,"height":180,"rx":86,"fill":89,"stroke":98,"style":127},[117,268,269],{"x":133,"y":263,"style":231},"02 Sep",[83,271],{"x":139,"y":260,"width":140,"height":180,"rx":86,"fill":89,"stroke":98,"style":127},[117,273,274],{"x":143,"y":263,"style":231},"103.06",[83,276],{"x":147,"y":260,"width":148,"height":180,"rx":86,"fill":89,"stroke":98,"style":127},[117,278,279],{"x":151,"y":263,"style":231},"103.21",[83,281],{"x":155,"y":260,"width":156,"height":180,"rx":86,"fill":89,"stroke":98,"style":127},[117,283,284],{"x":159,"y":263,"style":231},"101.82",[83,286],{"x":163,"y":260,"width":164,"height":180,"rx":86,"fill":89,"stroke":98,"style":127},[117,288,289],{"x":167,"y":263,"style":231},"102.25",[83,291],{"x":171,"y":260,"width":172,"height":180,"rx":86,"fill":89,"stroke":98,"style":127},[117,293,294],{"x":175,"y":263,"style":231},"11580",[83,296],{"x":92,"y":297,"width":125,"height":180,"rx":86,"fill":97,"stroke":98,"style":127},"154.0",[117,299,301],{"x":183,"y":300,"style":135},"173.0","4",[83,303],{"x":119,"y":297,"width":130,"height":180,"rx":86,"fill":89,"stroke":98,"style":127},[117,305,306],{"x":133,"y":300,"style":231},"03 Sep",[83,308],{"x":139,"y":297,"width":140,"height":180,"rx":86,"fill":89,"stroke":98,"style":127},[117,310,311],{"x":143,"y":300,"style":231},"99.23",[83,313],{"x":147,"y":297,"width":148,"height":180,"rx":86,"fill":89,"stroke":98,"style":127},[117,315,316],{"x":151,"y":300,"style":231},"102.55",[83,318],{"x":155,"y":297,"width":156,"height":180,"rx":86,"fill":89,"stroke":98,"style":127},[117,320,321],{"x":159,"y":300,"style":231},"99.04",[83,323],{"x":163,"y":297,"width":164,"height":180,"rx":86,"fill":89,"stroke":98,"style":127},[117,325,326],{"x":167,"y":300,"style":231},"102.33",[83,328],{"x":171,"y":297,"width":172,"height":180,"rx":86,"fill":89,"stroke":98,"style":127},[117,330,331],{"x":175,"y":300,"style":231},"11052",[37,333],{"x1":334,"y1":335,"x2":336,"y2":335,"stroke":195,"style":337},"484.8","99.0","516.8","stroke-width:2px",[339,340],"polygon",{"points":341,"fill":342},"520.8,99.0 511.8,104.0 511.8,94.0","#5b5cf0",[83,344],{"x":345,"y":346,"width":347,"height":348,"rx":349,"fill":350,"stroke":351,"style":337},"526.8","43.8","191.8","110.5","12","#fdefd8","var(--gold,#b4740a)",[106,353,355],{"transform":354},"translate(610.7,56.8) scale(1.000)",[110,356],{"d":357,"fill":113,"stroke":358,"style":359},"M12 3.5l9.5 17h-19z M12 10v5 M12 17.8v.4","var(--gold-ink,#7a4e06)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[117,361,365],{"x":362,"y":363,"style":364},"622.7","103.2","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Open, High, Low, Close",[117,367,370],{"x":362,"y":368,"style":369},"122.8","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","exactly this order",[117,372,374],{"x":362,"y":373,"style":369},"140.2","four adjacent columns",[20,376,378],{"id":377},"step-1-arrange-the-data-in-the-order-excel-expects","Step 1 — Arrange the data in the order Excel expects",[10,380,381],{},"Excel's stock charts identify the series by position, not by name: an open-high-low-close chart needs exactly four series in the order Open, High, Low, Close. A high-low-close chart needs three, in that order. If an export has the columns in another order, reorder them before writing:",[25,383,387],{"className":384,"code":385,"language":386,"meta":30,"style":30},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\n\nprices = pd.read_excel(\"prices.xlsx\", sheet_name=\"Prices\")\nprices = prices[[\"Date\", \"Open\", \"High\", \"Low\", \"Close\", \"Volume\"]]\nprint(prices.head(3).to_string(index=False))\nprint(len(prices), \"trading days\")\n","python",[32,388,389,405,412,442,483,509],{"__ignoreMap":30},[35,390,391,395,399,402],{"class":37,"line":38},[35,392,394],{"class":393},"s-kum","import",[35,396,398],{"class":397},"skGVy"," pandas ",[35,400,401],{"class":393},"as",[35,403,404],{"class":397}," pd\n",[35,406,408],{"class":37,"line":407},2,[35,409,411],{"emptyLinePlaceholder":410},true,"\n",[35,413,415,418,421,424,427,430,434,436,439],{"class":37,"line":414},3,[35,416,417],{"class":397},"prices ",[35,419,420],{"class":393},"=",[35,422,423],{"class":397}," pd.read_excel(",[35,425,426],{"class":45},"\"prices.xlsx\"",[35,428,429],{"class":397},", ",[35,431,433],{"class":432},"sa561","sheet_name",[35,435,420],{"class":393},[35,437,438],{"class":45},"\"Prices\"",[35,440,441],{"class":397},")\n",[35,443,445,447,449,452,455,457,460,462,465,467,470,472,475,477,480],{"class":37,"line":444},4,[35,446,417],{"class":397},[35,448,420],{"class":393},[35,450,451],{"class":397}," prices[[",[35,453,454],{"class":45},"\"Date\"",[35,456,429],{"class":397},[35,458,459],{"class":45},"\"Open\"",[35,461,429],{"class":397},[35,463,464],{"class":45},"\"High\"",[35,466,429],{"class":397},[35,468,469],{"class":45},"\"Low\"",[35,471,429],{"class":397},[35,473,474],{"class":45},"\"Close\"",[35,476,429],{"class":397},[35,478,479],{"class":45},"\"Volume\"",[35,481,482],{"class":397},"]]\n",[35,484,486,490,493,495,498,501,503,506],{"class":37,"line":485},5,[35,487,489],{"class":488},"sP0c6","print",[35,491,492],{"class":397},"(prices.head(",[35,494,264],{"class":488},[35,496,497],{"class":397},").to_string(",[35,499,500],{"class":432},"index",[35,502,420],{"class":393},[35,504,505],{"class":488},"False",[35,507,508],{"class":397},"))\n",[35,510,512,514,517,520,523,526],{"class":37,"line":511},6,[35,513,489],{"class":488},[35,515,516],{"class":397},"(",[35,518,519],{"class":488},"len",[35,521,522],{"class":397},"(prices), ",[35,524,525],{"class":45},"\"trading days\"",[35,527,441],{"class":397},[10,529,530],{},"With the columns in the wrong order, Excel draws the chart without complaint — but the boxes span the wrong prices, so a day that fell can appear to have risen. The column selection above makes the order explicit in code, where a later change to the export cannot silently break it.",[20,532,534],{"id":533},"step-2-build-the-candlestick-chart","Step 2 — Build the candlestick chart",[10,536,537],{},"Add the four price columns as series, hide their lines, and turn on the two features that make it a candlestick: high-low lines and up\u002Fdown bars:",[25,539,541],{"className":384,"code":540,"language":386,"meta":30,"style":30},"from openpyxl import load_workbook\nfrom openpyxl.chart import StockChart, Reference\nfrom openpyxl.chart.axis import ChartLines\nfrom openpyxl.chart.shapes import GraphicalProperties\nfrom openpyxl.chart.updown_bars import UpDownBars\n\nwb = load_workbook(\"prices.xlsx\")\nws = wb[\"Prices\"]\nlast = ws.max_row\nfor cell in ws[\"A\"][1:]:\n    cell.number_format = \"dd mmm\"\n\nchart = StockChart()\nchart.add_data(Reference(ws, min_col=2, max_col=5, min_row=1, max_row=last), titles_from_data=True)\nchart.set_categories(Reference(ws, min_col=1, min_row=2, max_row=last))\nfor series in chart.series:\n    series.graphicalProperties.line.noFill = True\nchart.hiLowLines = ChartLines()\nchart.upDownBars = UpDownBars(\n    gapWidth=60,\n    upBars=ChartLines(spPr=GraphicalProperties(solidFill=\"0F9488\")),\n    downBars=ChartLines(spPr=GraphicalProperties(solidFill=\"BE185D\")),\n)\nprint([s.tx.strRef.f for s in chart.series])\n",[32,542,543,556,568,580,592,604,608,623,639,650,676,687,692,703,755,784,797,808,819,830,844,874,899,904],{"__ignoreMap":30},[35,544,545,548,551,553],{"class":37,"line":38},[35,546,547],{"class":393},"from",[35,549,550],{"class":397}," openpyxl ",[35,552,394],{"class":393},[35,554,555],{"class":397}," load_workbook\n",[35,557,558,560,563,565],{"class":37,"line":407},[35,559,547],{"class":393},[35,561,562],{"class":397}," openpyxl.chart ",[35,564,394],{"class":393},[35,566,567],{"class":397}," StockChart, Reference\n",[35,569,570,572,575,577],{"class":37,"line":414},[35,571,547],{"class":393},[35,573,574],{"class":397}," openpyxl.chart.axis ",[35,576,394],{"class":393},[35,578,579],{"class":397}," ChartLines\n",[35,581,582,584,587,589],{"class":37,"line":444},[35,583,547],{"class":393},[35,585,586],{"class":397}," openpyxl.chart.shapes ",[35,588,394],{"class":393},[35,590,591],{"class":397}," GraphicalProperties\n",[35,593,594,596,599,601],{"class":37,"line":485},[35,595,547],{"class":393},[35,597,598],{"class":397}," openpyxl.chart.updown_bars ",[35,600,394],{"class":393},[35,602,603],{"class":397}," UpDownBars\n",[35,605,606],{"class":37,"line":511},[35,607,411],{"emptyLinePlaceholder":410},[35,609,611,614,616,619,621],{"class":37,"line":610},7,[35,612,613],{"class":397},"wb ",[35,615,420],{"class":393},[35,617,618],{"class":397}," load_workbook(",[35,620,426],{"class":45},[35,622,441],{"class":397},[35,624,626,629,631,634,636],{"class":37,"line":625},8,[35,627,628],{"class":397},"ws ",[35,630,420],{"class":393},[35,632,633],{"class":397}," wb[",[35,635,438],{"class":45},[35,637,638],{"class":397},"]\n",[35,640,642,645,647],{"class":37,"line":641},9,[35,643,644],{"class":397},"last ",[35,646,420],{"class":393},[35,648,649],{"class":397}," ws.max_row\n",[35,651,653,656,659,662,665,668,671,673],{"class":37,"line":652},10,[35,654,655],{"class":393},"for",[35,657,658],{"class":397}," cell ",[35,660,661],{"class":393},"in",[35,663,664],{"class":397}," ws[",[35,666,667],{"class":45},"\"A\"",[35,669,670],{"class":397},"][",[35,672,185],{"class":488},[35,674,675],{"class":397},":]:\n",[35,677,679,682,684],{"class":37,"line":678},11,[35,680,681],{"class":397},"    cell.number_format ",[35,683,420],{"class":393},[35,685,686],{"class":45}," \"dd mmm\"\n",[35,688,690],{"class":37,"line":689},12,[35,691,411],{"emptyLinePlaceholder":410},[35,693,695,698,700],{"class":37,"line":694},13,[35,696,697],{"class":397},"chart ",[35,699,420],{"class":393},[35,701,702],{"class":397}," StockChart()\n",[35,704,706,709,712,714,716,718,721,723,726,728,731,733,735,737,740,742,745,748,750,753],{"class":37,"line":705},14,[35,707,708],{"class":397},"chart.add_data(Reference(ws, ",[35,710,711],{"class":432},"min_col",[35,713,420],{"class":393},[35,715,226],{"class":488},[35,717,429],{"class":397},[35,719,720],{"class":432},"max_col",[35,722,420],{"class":393},[35,724,725],{"class":488},"5",[35,727,429],{"class":397},[35,729,730],{"class":432},"min_row",[35,732,420],{"class":393},[35,734,185],{"class":488},[35,736,429],{"class":397},[35,738,739],{"class":432},"max_row",[35,741,420],{"class":393},[35,743,744],{"class":397},"last), ",[35,746,747],{"class":432},"titles_from_data",[35,749,420],{"class":393},[35,751,752],{"class":488},"True",[35,754,441],{"class":397},[35,756,758,761,763,765,767,769,771,773,775,777,779,781],{"class":37,"line":757},15,[35,759,760],{"class":397},"chart.set_categories(Reference(ws, ",[35,762,711],{"class":432},[35,764,420],{"class":393},[35,766,185],{"class":488},[35,768,429],{"class":397},[35,770,730],{"class":432},[35,772,420],{"class":393},[35,774,226],{"class":488},[35,776,429],{"class":397},[35,778,739],{"class":432},[35,780,420],{"class":393},[35,782,783],{"class":397},"last))\n",[35,785,787,789,792,794],{"class":37,"line":786},16,[35,788,655],{"class":393},[35,790,791],{"class":397}," series ",[35,793,661],{"class":393},[35,795,796],{"class":397}," chart.series:\n",[35,798,800,803,805],{"class":37,"line":799},17,[35,801,802],{"class":397},"    series.graphicalProperties.line.noFill ",[35,804,420],{"class":393},[35,806,807],{"class":488}," True\n",[35,809,811,814,816],{"class":37,"line":810},18,[35,812,813],{"class":397},"chart.hiLowLines ",[35,815,420],{"class":393},[35,817,818],{"class":397}," ChartLines()\n",[35,820,822,825,827],{"class":37,"line":821},19,[35,823,824],{"class":397},"chart.upDownBars ",[35,826,420],{"class":393},[35,828,829],{"class":397}," UpDownBars(\n",[35,831,833,836,838,841],{"class":37,"line":832},20,[35,834,835],{"class":432},"    gapWidth",[35,837,420],{"class":393},[35,839,840],{"class":488},"60",[35,842,843],{"class":397},",\n",[35,845,847,850,852,855,858,860,863,866,868,871],{"class":37,"line":846},21,[35,848,849],{"class":432},"    upBars",[35,851,420],{"class":393},[35,853,854],{"class":397},"ChartLines(",[35,856,857],{"class":432},"spPr",[35,859,420],{"class":393},[35,861,862],{"class":397},"GraphicalProperties(",[35,864,865],{"class":432},"solidFill",[35,867,420],{"class":393},[35,869,870],{"class":45},"\"0F9488\"",[35,872,873],{"class":397},")),\n",[35,875,877,880,882,884,886,888,890,892,894,897],{"class":37,"line":876},22,[35,878,879],{"class":432},"    downBars",[35,881,420],{"class":393},[35,883,854],{"class":397},[35,885,857],{"class":432},[35,887,420],{"class":393},[35,889,862],{"class":397},[35,891,865],{"class":432},[35,893,420],{"class":393},[35,895,896],{"class":45},"\"BE185D\"",[35,898,873],{"class":397},[35,900,902],{"class":37,"line":901},23,[35,903,441],{"class":397},[35,905,907,909,912,914,917,919],{"class":37,"line":906},24,[35,908,489],{"class":488},[35,910,911],{"class":397},"([s.tx.strRef.f ",[35,913,655],{"class":393},[35,915,916],{"class":397}," s ",[35,918,661],{"class":393},[35,920,921],{"class":397}," chart.series])\n",[10,923,924,925,928,929,932,933,936,937,940],{},"Without ",[32,926,927],{},"line.noFill",", Excel joins each series' points with a line, and the chart becomes four zigzags across the candles. ",[32,930,931],{},"hiLowLines"," draws the vertical line from the day's high to its low. ",[32,934,935],{},"upDownBars"," draws the box between the first and last series — open and close — and colours it by direction: here teal for days that closed higher than they opened and pink for days that closed lower, instead of Excel's default white and black. ",[32,938,939],{},"gapWidth"," sets the space between the boxes as a percentage of their width; lower values give wider candles.",[20,942,944],{"id":943},"step-3-axes-no-zero-no-weekends","Step 3 — Axes: no zero, no weekends",[10,946,947],{},"A price chart starting at zero squeezes all the movement into a thin band at the top. Start the value axis just below the lowest low, and make sure both axes are displayed:",[25,949,951],{"className":384,"code":950,"language":386,"meta":30,"style":30},"low = prices[\"Low\"].min()\nchart.y_axis.scaling.min = int(low) - 1\nchart.y_axis.title = \"Price\"\nchart.y_axis.delete = False\nchart.x_axis.delete = False\nchart.x_axis.number_format = \"dd mmm\"\nchart.legend = None\nchart.title = \"ACME daily prices\"\nchart.width, chart.height = 16, 9\nws.add_chart(chart, \"H2\")\nprint(\"y axis from\", chart.y_axis.scaling.min)\n",[32,952,953,968,987,997,1007,1016,1025,1035,1045,1060,1070],{"__ignoreMap":30},[35,954,955,958,960,963,965],{"class":37,"line":38},[35,956,957],{"class":397},"low ",[35,959,420],{"class":393},[35,961,962],{"class":397}," prices[",[35,964,469],{"class":45},[35,966,967],{"class":397},"].min()\n",[35,969,970,973,975,978,981,984],{"class":37,"line":407},[35,971,972],{"class":397},"chart.y_axis.scaling.min ",[35,974,420],{"class":393},[35,976,977],{"class":488}," int",[35,979,980],{"class":397},"(low) ",[35,982,983],{"class":393},"-",[35,985,986],{"class":488}," 1\n",[35,988,989,992,994],{"class":37,"line":414},[35,990,991],{"class":397},"chart.y_axis.title ",[35,993,420],{"class":393},[35,995,996],{"class":45}," \"Price\"\n",[35,998,999,1002,1004],{"class":37,"line":444},[35,1000,1001],{"class":397},"chart.y_axis.delete ",[35,1003,420],{"class":393},[35,1005,1006],{"class":488}," False\n",[35,1008,1009,1012,1014],{"class":37,"line":485},[35,1010,1011],{"class":397},"chart.x_axis.delete ",[35,1013,420],{"class":393},[35,1015,1006],{"class":488},[35,1017,1018,1021,1023],{"class":37,"line":511},[35,1019,1020],{"class":397},"chart.x_axis.number_format ",[35,1022,420],{"class":393},[35,1024,686],{"class":45},[35,1026,1027,1030,1032],{"class":37,"line":610},[35,1028,1029],{"class":397},"chart.legend ",[35,1031,420],{"class":393},[35,1033,1034],{"class":488}," None\n",[35,1036,1037,1040,1042],{"class":37,"line":625},[35,1038,1039],{"class":397},"chart.title ",[35,1041,420],{"class":393},[35,1043,1044],{"class":45}," \"ACME daily prices\"\n",[35,1046,1047,1050,1052,1055,1057],{"class":37,"line":641},[35,1048,1049],{"class":397},"chart.width, chart.height ",[35,1051,420],{"class":393},[35,1053,1054],{"class":488}," 16",[35,1056,429],{"class":397},[35,1058,1059],{"class":488},"9\n",[35,1061,1062,1065,1068],{"class":37,"line":652},[35,1063,1064],{"class":397},"ws.add_chart(chart, ",[35,1066,1067],{"class":45},"\"H2\"",[35,1069,441],{"class":397},[35,1071,1072,1074,1076,1079],{"class":37,"line":678},[35,1073,489],{"class":488},[35,1075,516],{"class":397},[35,1077,1078],{"class":45},"\"y axis from\"",[35,1080,1081],{"class":397},", chart.y_axis.scaling.min)\n",[10,1083,1084,1085,1088,1089,1092,1093,1097,1098,1101],{},"The category axis here is a ",[1086,1087,117],"em",{}," axis: one slot per row, so the twenty trading days sit next to each other with no gaps for weekends. A ",[1086,1090,1091],{},"date"," axis would space the points by calendar date and leave empty slots for every Saturday and Sunday — right for irregular events, wrong for trading days. openpyxl's stock chart uses a text axis by default, so the only thing to do is not to change it. ",[14,1094,1096],{"href":1095},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fuse-a-date-axis-in-an-excel-chart-with-openpyxl\u002F","Use a Date Axis in an Excel Chart with openpyxl"," covers the other case. The legend is removed because four entries named Open, High, Low and Close explain nothing about a candlestick chart. The ",[32,1099,1100],{},"delete = False"," settings make Excel show the axes, which openpyxl otherwise writes as hidden.",[64,1103,73,1109,73,1112,73,1115,73,1120,73,1125,73,1132,73,1138,73,1142,73,1146,73,1149,73,1151,73,1158,73,1163,73,1167,73,1171,73,1174,73,1179,73,1185,73,1190],{"viewBox":1104,"role":67,"ariaLabelledBy":1105,"xmlns":71,"style":1108},"64 0 632 383",[1106,1107],"st-parts-t","st-parts-d","width:100%;max-width:632px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[75,1110,1111],{"id":1106},"The pieces of one candle",[79,1113,1114],{"id":1107},"Three layers explaining a candle. The high-low line spans the day's range, the up-down bar spans open to close, and its colour shows whether the day closed higher or lower than it opened.",[83,1116],{"x":1117,"y":86,"width":1118,"height":1119,"fill":89},"64","632","383",[83,1121],{"x":1122,"y":93,"width":1123,"height":1124,"rx":349,"fill":97,"stroke":98,"style":337},"80.0","600.0","93.0",[106,1126,1128],{"transform":1127},"translate(368.0,29.0) scale(1.000)",[110,1129],{"d":1130,"fill":113,"stroke":1131,"style":359},"M4 20h16 M4 20V4 M6 16l4-5 4 3 6-7","var(--text,#172033)",[117,1133,1137],{"x":1134,"y":1135,"style":1136},"380.0","75.5","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","High-low line",[117,1139,1141],{"x":1134,"y":1140,"style":369},"95.0","hiLowLines — from the day's low to its high",[37,1143],{"x1":1134,"y1":1144,"x2":1134,"y2":1145,"stroke":195,"style":337},"114.0","136.0",[339,1147],{"points":1148,"fill":342},"380.0,140.0 375.0,131.0 385.0,131.0",[83,1150],{"x":1122,"y":263,"width":1123,"height":1124,"rx":349,"fill":194,"stroke":195,"style":337},[106,1152,1154],{"transform":1153},"translate(368.0,158.0) scale(1.000)",[110,1155],{"d":1156,"fill":113,"stroke":1157,"style":359},"M12 3l9 5-9 5-9-5z M3 13l9 5 9-5 M3 17l9 5 9-5","var(--brand-strong,#4338ca)",[117,1159,1162],{"x":1134,"y":1160,"style":1161},"204.5","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Up\u002Fdown bar",[117,1164,1166],{"x":1134,"y":1165,"style":369},"224.0","upDownBars — the box between open and close",[37,1168],{"x1":1134,"y1":1169,"x2":1134,"y2":1170,"stroke":195,"style":337},"243.0","265.0",[339,1172],{"points":1173,"fill":342},"380.0,269.0 375.0,260.0 385.0,260.0",[83,1175],{"x":1122,"y":1176,"width":1123,"height":1124,"rx":349,"fill":1177,"stroke":1178,"style":337},"274.0","#d9f4f1","var(--teal,#0f9488)",[106,1180,1182],{"transform":1181},"translate(368.0,287.0) scale(1.000)",[110,1183],{"d":1184,"fill":113,"stroke":114,"style":359},"M5 12.5l4.5 4.5L19 7",[117,1186,1189],{"x":1134,"y":1187,"style":1188},"333.5","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Colour",[117,1191,1193],{"x":1134,"y":1192,"style":369},"353.0","teal when close > open, pink when close \u003C open",[20,1195,1197],{"id":1196},"step-4-add-a-volume-chart-underneath","Step 4 — Add a volume chart underneath",[10,1199,1200],{},"Excel can combine volume bars with the candles on a secondary axis, but the combination is fragile to build from code and cramped to read. A separate column chart of volume, the same width and directly below the candles with the same categories, reads more clearly:",[25,1202,1204],{"className":384,"code":1203,"language":386,"meta":30,"style":30},"from openpyxl.chart import BarChart\n\nvolume = BarChart()\nvolume.add_data(Reference(ws, min_col=6, min_row=1, max_row=last), titles_from_data=True)\nvolume.set_categories(Reference(ws, min_col=1, min_row=2, max_row=last))\nvolume.series[0].graphicalProperties.solidFill = \"94A3B8\"\nvolume.series[0].graphicalProperties.line.noFill = True\nvolume.gapWidth = 60\nvolume.legend = None\nvolume.title = \"Volume\"\nvolume.y_axis.delete = False\nvolume.x_axis.delete = False\nvolume.x_axis.number_format = \"dd mmm\"\nvolume.width, volume.height = 16, 5\nws.add_chart(volume, \"H20\")\n\nws.page_setup.orientation = \"landscape\"\nws.sheet_properties.pageSetUpPr.fitToPage = True\nws.page_setup.fitToWidth, ws.page_setup.fitToHeight = 1, 1\nwb.save(\"prices_chart.xlsx\")\nprint(\"saved\")\n",[32,1205,1206,1217,1221,1231,1267,1294,1309,1322,1332,1341,1351,1360,1369,1378,1392,1402,1406,1416,1425,1440,1450],{"__ignoreMap":30},[35,1207,1208,1210,1212,1214],{"class":37,"line":38},[35,1209,547],{"class":393},[35,1211,562],{"class":397},[35,1213,394],{"class":393},[35,1215,1216],{"class":397}," BarChart\n",[35,1218,1219],{"class":37,"line":407},[35,1220,411],{"emptyLinePlaceholder":410},[35,1222,1223,1226,1228],{"class":37,"line":414},[35,1224,1225],{"class":397},"volume ",[35,1227,420],{"class":393},[35,1229,1230],{"class":397}," BarChart()\n",[35,1232,1233,1236,1238,1240,1243,1245,1247,1249,1251,1253,1255,1257,1259,1261,1263,1265],{"class":37,"line":444},[35,1234,1235],{"class":397},"volume.add_data(Reference(ws, ",[35,1237,711],{"class":432},[35,1239,420],{"class":393},[35,1241,1242],{"class":488},"6",[35,1244,429],{"class":397},[35,1246,730],{"class":432},[35,1248,420],{"class":393},[35,1250,185],{"class":488},[35,1252,429],{"class":397},[35,1254,739],{"class":432},[35,1256,420],{"class":393},[35,1258,744],{"class":397},[35,1260,747],{"class":432},[35,1262,420],{"class":393},[35,1264,752],{"class":488},[35,1266,441],{"class":397},[35,1268,1269,1272,1274,1276,1278,1280,1282,1284,1286,1288,1290,1292],{"class":37,"line":485},[35,1270,1271],{"class":397},"volume.set_categories(Reference(ws, ",[35,1273,711],{"class":432},[35,1275,420],{"class":393},[35,1277,185],{"class":488},[35,1279,429],{"class":397},[35,1281,730],{"class":432},[35,1283,420],{"class":393},[35,1285,226],{"class":488},[35,1287,429],{"class":397},[35,1289,739],{"class":432},[35,1291,420],{"class":393},[35,1293,783],{"class":397},[35,1295,1296,1299,1301,1304,1306],{"class":37,"line":511},[35,1297,1298],{"class":397},"volume.series[",[35,1300,86],{"class":488},[35,1302,1303],{"class":397},"].graphicalProperties.solidFill ",[35,1305,420],{"class":393},[35,1307,1308],{"class":45}," \"94A3B8\"\n",[35,1310,1311,1313,1315,1318,1320],{"class":37,"line":610},[35,1312,1298],{"class":397},[35,1314,86],{"class":488},[35,1316,1317],{"class":397},"].graphicalProperties.line.noFill ",[35,1319,420],{"class":393},[35,1321,807],{"class":488},[35,1323,1324,1327,1329],{"class":37,"line":625},[35,1325,1326],{"class":397},"volume.gapWidth ",[35,1328,420],{"class":393},[35,1330,1331],{"class":488}," 60\n",[35,1333,1334,1337,1339],{"class":37,"line":641},[35,1335,1336],{"class":397},"volume.legend ",[35,1338,420],{"class":393},[35,1340,1034],{"class":488},[35,1342,1343,1346,1348],{"class":37,"line":652},[35,1344,1345],{"class":397},"volume.title ",[35,1347,420],{"class":393},[35,1349,1350],{"class":45}," \"Volume\"\n",[35,1352,1353,1356,1358],{"class":37,"line":678},[35,1354,1355],{"class":397},"volume.y_axis.delete ",[35,1357,420],{"class":393},[35,1359,1006],{"class":488},[35,1361,1362,1365,1367],{"class":37,"line":689},[35,1363,1364],{"class":397},"volume.x_axis.delete ",[35,1366,420],{"class":393},[35,1368,1006],{"class":488},[35,1370,1371,1374,1376],{"class":37,"line":694},[35,1372,1373],{"class":397},"volume.x_axis.number_format ",[35,1375,420],{"class":393},[35,1377,686],{"class":45},[35,1379,1380,1383,1385,1387,1389],{"class":37,"line":705},[35,1381,1382],{"class":397},"volume.width, volume.height ",[35,1384,420],{"class":393},[35,1386,1054],{"class":488},[35,1388,429],{"class":397},[35,1390,1391],{"class":488},"5\n",[35,1393,1394,1397,1400],{"class":37,"line":757},[35,1395,1396],{"class":397},"ws.add_chart(volume, ",[35,1398,1399],{"class":45},"\"H20\"",[35,1401,441],{"class":397},[35,1403,1404],{"class":37,"line":786},[35,1405,411],{"emptyLinePlaceholder":410},[35,1407,1408,1411,1413],{"class":37,"line":799},[35,1409,1410],{"class":397},"ws.page_setup.orientation ",[35,1412,420],{"class":393},[35,1414,1415],{"class":45}," \"landscape\"\n",[35,1417,1418,1421,1423],{"class":37,"line":810},[35,1419,1420],{"class":397},"ws.sheet_properties.pageSetUpPr.fitToPage ",[35,1422,420],{"class":393},[35,1424,807],{"class":488},[35,1426,1427,1430,1432,1435,1437],{"class":37,"line":821},[35,1428,1429],{"class":397},"ws.page_setup.fitToWidth, ws.page_setup.fitToHeight ",[35,1431,420],{"class":393},[35,1433,1434],{"class":488}," 1",[35,1436,429],{"class":397},[35,1438,1439],{"class":488},"1\n",[35,1441,1442,1445,1448],{"class":37,"line":832},[35,1443,1444],{"class":397},"wb.save(",[35,1446,1447],{"class":45},"\"prices_chart.xlsx\"",[35,1449,441],{"class":397},[35,1451,1452,1454,1456,1459],{"class":37,"line":846},[35,1453,489],{"class":488},[35,1455,516],{"class":397},[35,1457,1458],{"class":45},"\"saved\"",[35,1460,441],{"class":397},[10,1462,1463,1464,1467,1468,1470,1471,1474,1475,1478],{},"Matching ",[32,1465,1466],{},"width"," and ",[32,1469,939],{}," lines the volume bars up under the candles, day for day — closely rather than exactly, because the two charts' value axes have labels of different widths (prices like ",[32,1472,1473],{},"104"," against volumes like ",[32,1476,1477],{},"25000","), which shifts each plot area slightly. A neutral grey keeps volume visually secondary to the price.",[20,1480,1482],{"id":1481},"step-5-render-and-check","Step 5 — Render and check",[10,1484,1485],{},"Convert to PDF with LibreOffice and look at the result before sending it anywhere. The landscape, fit-to-one-page setup at the end of Step 4 keeps the charts to the right of the data on the same printed page — set it in the same session that adds the charts, because reopening a workbook with openpyxl drops its charts:",[25,1487,1489],{"className":27,"code":1488,"language":29,"meta":30,"style":30},"soffice -env:UserInstallation=file:\u002F\u002F$PWD\u002Flo_profile --headless --convert-to pdf prices_chart.xlsx > \u002Fdev\u002Fnull 2>&1\npdftoppm -png -r 50 -f 1 -l 1 prices_chart.pdf preview && ls preview*\n",[32,1490,1491,1526],{"__ignoreMap":30},[35,1492,1493,1496,1499,1502,1505,1508,1511,1514,1517,1520,1523],{"class":37,"line":38},[35,1494,1495],{"class":41},"soffice",[35,1497,1498],{"class":488}," -env:UserInstallation=file:\u002F\u002F",[35,1500,1501],{"class":397},"$PWD",[35,1503,1504],{"class":488},"\u002Flo_profile",[35,1506,1507],{"class":488}," --headless",[35,1509,1510],{"class":488}," --convert-to",[35,1512,1513],{"class":45}," pdf",[35,1515,1516],{"class":45}," prices_chart.xlsx",[35,1518,1519],{"class":393}," >",[35,1521,1522],{"class":45}," \u002Fdev\u002Fnull",[35,1524,1525],{"class":393}," 2>&1\n",[35,1527,1528,1531,1534,1537,1540,1543,1545,1548,1550,1553,1556,1559,1562,1564],{"class":37,"line":407},[35,1529,1530],{"class":41},"pdftoppm",[35,1532,1533],{"class":488}," -png",[35,1535,1536],{"class":488}," -r",[35,1538,1539],{"class":488}," 50",[35,1541,1542],{"class":488}," -f",[35,1544,1434],{"class":488},[35,1546,1547],{"class":488}," -l",[35,1549,1434],{"class":488},[35,1551,1552],{"class":45}," prices_chart.pdf",[35,1554,1555],{"class":45}," preview",[35,1557,1558],{"class":397}," && ",[35,1560,1561],{"class":41},"ls",[35,1563,1555],{"class":45},[35,1565,1566],{"class":488},"*\n",[10,1568,1569],{},"The render shows teal and pink candles with their wicks, pink days clustering in the second half of the month, a value axis from just below the lowest price, dates without weekend gaps, and the volume bars aligned underneath.",[64,1571,73,1577,73,1580,73,1583,73,1587,73,1593,73,1600,73,1606,73,1610,73,1614,73,1618,73,1622,73,1625,73,1630,73,1635,73,1639,73,1642,73,1645],{"viewBox":1572,"role":67,"ariaLabelledBy":1573,"xmlns":71,"style":1576},"4 0 752 207",[1574,1575],"st-variants-t","st-variants-d","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[75,1578,1579],{"id":1574},"Which stock chart layout",[79,1581,1582],{"id":1575},"Two panels. Open-high-low-close needs four columns and draws candles with up and down bars. High-low-close needs three columns and draws a range line with a marker for the close.",[83,1584],{"x":301,"y":86,"width":1585,"height":1586,"fill":89},"752","207",[83,1588],{"x":1589,"y":93,"width":1590,"height":1591,"rx":1592,"fill":194,"stroke":195,"style":337},"20.0","351.0","175.0","14",[106,1594,1596],{"transform":1595},"translate(182.5,29.0) scale(1.083)",[110,1597],{"d":1598,"fill":113,"stroke":1157,"style":1599},"M4 20h16 M7 17v-5 M12 17V7 M17 17v-8","stroke-width:1.66px;stroke-linecap:round;stroke-linejoin:round",[117,1601,1605],{"x":1602,"y":1603,"style":1604},"195.5","78.0","font-size:14px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Open-High-Low-Close",[37,1607],{"x1":120,"y1":1608,"x2":1609,"y2":1608,"stroke":195,"style":127},"91.0","355.0",[117,1611,1613],{"x":1602,"y":1612,"style":231},"111.0","4 series in that order",[117,1615,1617],{"x":1602,"y":1616,"style":231},"137.0","hiLowLines + upDownBars",[117,1619,1621],{"x":1602,"y":1620,"style":231},"163.0","shows direction per day",[83,1623],{"x":1624,"y":93,"width":1590,"height":1591,"rx":1592,"fill":1177,"stroke":1178,"style":337},"389.0",[106,1626,1628],{"transform":1627},"translate(551.5,29.0) scale(1.083)",[110,1629],{"d":1130,"fill":113,"stroke":114,"style":1599},[117,1631,1634],{"x":1632,"y":1603,"style":1633},"564.5","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","High-Low-Close",[37,1636],{"x1":1637,"y1":1608,"x2":1638,"y2":1608,"stroke":1178,"style":127},"405.0","724.0",[117,1640,1641],{"x":1632,"y":1612,"style":231},"3 series in that order",[117,1643,1644],{"x":1632,"y":1616,"style":231},"hiLowLines + close marker",[117,1646,1647],{"x":1632,"y":1620,"style":231},"when there is no open price",[20,1649,1651],{"id":1650},"a-high-low-close-chart-when-there-is-no-open-price","A high-low-close chart when there is no open price",[10,1653,1654],{},"Some sources record only a daily high, low and closing value — sensor logs and many price feeds do. The same chart type works with three series in the order High, Low, Close: keep the high-low lines, leave out the up\u002Fdown bars (there is no open to compare with), and show the close as a marker:",[25,1656,1658],{"className":384,"code":1657,"language":386,"meta":30,"style":30},"wb = load_workbook(\"prices.xlsx\")\nws = wb[\"Prices\"]\nfor cell in ws[\"A\"][1:]:\n    cell.number_format = \"dd mmm\"\nhlc = StockChart()\nhlc.add_data(Reference(ws, min_col=3, max_col=5, min_row=1, max_row=ws.max_row), titles_from_data=True)\nhlc.set_categories(Reference(ws, min_col=1, min_row=2, max_row=ws.max_row))\nfor series in hlc.series:\n    series.graphicalProperties.line.noFill = True\nclose = hlc.series[2]\nclose.marker.symbol = \"dash\"\nclose.marker.size = 8\nclose.marker.graphicalProperties.solidFill = \"4338CA\"\nhlc.hiLowLines = ChartLines()\nhlc.y_axis.scaling.min = int(low) - 1\nhlc.x_axis.delete = hlc.y_axis.delete = False\nhlc.x_axis.number_format = \"dd mmm\"\nhlc.legend = None\nhlc.width, hlc.height = 16, 8\nws.add_chart(hlc, \"A24\")\nwb.save(\"prices_hlc.xlsx\")\nprint(len(hlc.series), \"series:\", [s.tx.strRef.f for s in hlc.series])\n",[32,1659,1660,1672,1684,1702,1710,1719,1763,1791,1802,1810,1824,1834,1844,1854,1863,1878,1892,1901,1910,1924,1934,1943],{"__ignoreMap":30},[35,1661,1662,1664,1666,1668,1670],{"class":37,"line":38},[35,1663,613],{"class":397},[35,1665,420],{"class":393},[35,1667,618],{"class":397},[35,1669,426],{"class":45},[35,1671,441],{"class":397},[35,1673,1674,1676,1678,1680,1682],{"class":37,"line":407},[35,1675,628],{"class":397},[35,1677,420],{"class":393},[35,1679,633],{"class":397},[35,1681,438],{"class":45},[35,1683,638],{"class":397},[35,1685,1686,1688,1690,1692,1694,1696,1698,1700],{"class":37,"line":414},[35,1687,655],{"class":393},[35,1689,658],{"class":397},[35,1691,661],{"class":393},[35,1693,664],{"class":397},[35,1695,667],{"class":45},[35,1697,670],{"class":397},[35,1699,185],{"class":488},[35,1701,675],{"class":397},[35,1703,1704,1706,1708],{"class":37,"line":444},[35,1705,681],{"class":397},[35,1707,420],{"class":393},[35,1709,686],{"class":45},[35,1711,1712,1715,1717],{"class":37,"line":485},[35,1713,1714],{"class":397},"hlc ",[35,1716,420],{"class":393},[35,1718,702],{"class":397},[35,1720,1721,1724,1726,1728,1730,1732,1734,1736,1738,1740,1742,1744,1746,1748,1750,1752,1755,1757,1759,1761],{"class":37,"line":511},[35,1722,1723],{"class":397},"hlc.add_data(Reference(ws, ",[35,1725,711],{"class":432},[35,1727,420],{"class":393},[35,1729,264],{"class":488},[35,1731,429],{"class":397},[35,1733,720],{"class":432},[35,1735,420],{"class":393},[35,1737,725],{"class":488},[35,1739,429],{"class":397},[35,1741,730],{"class":432},[35,1743,420],{"class":393},[35,1745,185],{"class":488},[35,1747,429],{"class":397},[35,1749,739],{"class":432},[35,1751,420],{"class":393},[35,1753,1754],{"class":397},"ws.max_row), ",[35,1756,747],{"class":432},[35,1758,420],{"class":393},[35,1760,752],{"class":488},[35,1762,441],{"class":397},[35,1764,1765,1768,1770,1772,1774,1776,1778,1780,1782,1784,1786,1788],{"class":37,"line":610},[35,1766,1767],{"class":397},"hlc.set_categories(Reference(ws, ",[35,1769,711],{"class":432},[35,1771,420],{"class":393},[35,1773,185],{"class":488},[35,1775,429],{"class":397},[35,1777,730],{"class":432},[35,1779,420],{"class":393},[35,1781,226],{"class":488},[35,1783,429],{"class":397},[35,1785,739],{"class":432},[35,1787,420],{"class":393},[35,1789,1790],{"class":397},"ws.max_row))\n",[35,1792,1793,1795,1797,1799],{"class":37,"line":625},[35,1794,655],{"class":393},[35,1796,791],{"class":397},[35,1798,661],{"class":393},[35,1800,1801],{"class":397}," hlc.series:\n",[35,1803,1804,1806,1808],{"class":37,"line":641},[35,1805,802],{"class":397},[35,1807,420],{"class":393},[35,1809,807],{"class":488},[35,1811,1812,1815,1817,1820,1822],{"class":37,"line":652},[35,1813,1814],{"class":397},"close ",[35,1816,420],{"class":393},[35,1818,1819],{"class":397}," hlc.series[",[35,1821,226],{"class":488},[35,1823,638],{"class":397},[35,1825,1826,1829,1831],{"class":37,"line":678},[35,1827,1828],{"class":397},"close.marker.symbol ",[35,1830,420],{"class":393},[35,1832,1833],{"class":45}," \"dash\"\n",[35,1835,1836,1839,1841],{"class":37,"line":689},[35,1837,1838],{"class":397},"close.marker.size ",[35,1840,420],{"class":393},[35,1842,1843],{"class":488}," 8\n",[35,1845,1846,1849,1851],{"class":37,"line":694},[35,1847,1848],{"class":397},"close.marker.graphicalProperties.solidFill ",[35,1850,420],{"class":393},[35,1852,1853],{"class":45}," \"4338CA\"\n",[35,1855,1856,1859,1861],{"class":37,"line":705},[35,1857,1858],{"class":397},"hlc.hiLowLines ",[35,1860,420],{"class":393},[35,1862,818],{"class":397},[35,1864,1865,1868,1870,1872,1874,1876],{"class":37,"line":757},[35,1866,1867],{"class":397},"hlc.y_axis.scaling.min ",[35,1869,420],{"class":393},[35,1871,977],{"class":488},[35,1873,980],{"class":397},[35,1875,983],{"class":393},[35,1877,986],{"class":488},[35,1879,1880,1883,1885,1888,1890],{"class":37,"line":786},[35,1881,1882],{"class":397},"hlc.x_axis.delete ",[35,1884,420],{"class":393},[35,1886,1887],{"class":397}," hlc.y_axis.delete ",[35,1889,420],{"class":393},[35,1891,1006],{"class":488},[35,1893,1894,1897,1899],{"class":37,"line":799},[35,1895,1896],{"class":397},"hlc.x_axis.number_format ",[35,1898,420],{"class":393},[35,1900,686],{"class":45},[35,1902,1903,1906,1908],{"class":37,"line":810},[35,1904,1905],{"class":397},"hlc.legend ",[35,1907,420],{"class":393},[35,1909,1034],{"class":488},[35,1911,1912,1915,1917,1919,1921],{"class":37,"line":821},[35,1913,1914],{"class":397},"hlc.width, hlc.height ",[35,1916,420],{"class":393},[35,1918,1054],{"class":488},[35,1920,429],{"class":397},[35,1922,1923],{"class":488},"8\n",[35,1925,1926,1929,1932],{"class":37,"line":832},[35,1927,1928],{"class":397},"ws.add_chart(hlc, ",[35,1930,1931],{"class":45},"\"A24\"",[35,1933,441],{"class":397},[35,1935,1936,1938,1941],{"class":37,"line":846},[35,1937,1444],{"class":397},[35,1939,1940],{"class":45},"\"prices_hlc.xlsx\"",[35,1942,441],{"class":397},[35,1944,1945,1947,1949,1951,1954,1957,1960,1962,1964,1966],{"class":37,"line":876},[35,1946,489],{"class":488},[35,1948,516],{"class":397},[35,1950,519],{"class":488},[35,1952,1953],{"class":397},"(hlc.series), ",[35,1955,1956],{"class":45},"\"series:\"",[35,1958,1959],{"class":397},", [s.tx.strRef.f ",[35,1961,655],{"class":393},[35,1963,916],{"class":397},[35,1965,661],{"class":393},[35,1967,1968],{"class":397}," hlc.series])\n",[10,1970,1971],{},"A short horizontal dash on each high-low line marks where the day closed. It is the chart to use for any daily range with a representative end value, not only for prices.",[20,1973,1975],{"id":1974},"common-pitfalls","Common pitfalls",[1977,1978,1979,1987,1997,2005,2011],"ul",{},[1980,1981,1982,1986],"li",{},[1983,1984,1985],"strong",{},"Series in the wrong order."," Excel assigns roles by position; select the columns explicitly as Open, High, Low, Close.",[1980,1988,1989,1992,1993,1996],{},[1983,1990,1991],{},"Zigzag lines across the candles."," Set ",[32,1994,1995],{},"line.noFill = True"," on every series.",[1980,1998,1999,1992,2002,2004],{},[1983,2000,2001],{},"Hidden axes in Excel.",[32,2003,1100],{}," on both axes.",[1980,2006,2007,2010],{},[1983,2008,2009],{},"Weekend gaps."," Keep the default text axis for trading days; a date axis adds empty slots.",[1980,2012,2013,2016],{},[1983,2014,2015],{},"Re-saving with openpyxl."," Loading a workbook drops its charts; add charts in the final save.",[20,2018,2020],{"id":2019},"conclusion","Conclusion",[10,2022,2023,2024,2027,2028,2031,2032,1467,2034,2036,2037,2039],{},"Put the price columns in the order Open, High, Low, Close, add them to a ",[32,2025,2026],{},"StockChart"," with ",[32,2029,2030],{},"titles_from_data=True",", hide every series line, and turn on ",[32,2033,931],{},[32,2035,935],{}," with your own up and down colours. Start the value axis just below the lowest low, keep the text axis so trading days sit together, set ",[32,2038,1100],{}," on the axes and drop the legend. Put volume in a matching column chart underneath, and render with LibreOffice to check.",[20,2041,2043],{"id":2042},"frequently-asked-questions","Frequently asked questions",[10,2045,2046,2049],{},[1983,2047,2048],{},"How do I create a candlestick chart in Excel with Python?","\nUse openpyxl's StockChart with four series in the order Open, High, Low, Close, set each series' line to noFill, and set chart.hiLowLines = ChartLines() and chart.upDownBars = UpDownBars(). Add the dates as categories.",[10,2051,2052,2055,2056,2058,2059,2062],{},[1983,2053,2054],{},"Why does my stock chart show lines instead of candles?","\nThe series lines are still drawn. Set ",[32,2057,1995],{}," on each series' ",[32,2060,2061],{},"graphicalProperties","; the candles come from the high-low lines and up-down bars.",[10,2064,2065,2068,2069,2072],{},[1983,2066,2067],{},"How do I change the colours of rising and falling days?","\nPass upBars and downBars to UpDownBars, each a ChartLines whose spPr is a GraphicalProperties with the fill colour you want, such as ",[32,2070,2071],{},"GraphicalProperties(solidFill=\"0F9488\")",".",[10,2074,2075,2078],{},[1983,2076,2077],{},"How do I stop weekends showing as gaps?","\nUse a text category axis, which is the stock chart's default in openpyxl: it gives one slot per row, so only the dates in the data appear. A date axis spaces points by calendar date and leaves weekend gaps.",[20,2080,2082],{"id":2081},"related","Related",[1977,2084,2085,2091,2098,2105],{},[1980,2086,2087,2088,2090],{},"Up one level: ",[14,2089,17],{"href":16}," — every chart type openpyxl supports.",[1980,2092,2093,2097],{},[14,2094,2096],{"href":2095},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fadd-line-chart-to-excel-report-with-python\u002F","Add a Line Chart to an Excel Report with Python"," — a simpler way to show a closing price over time.",[1980,2099,2100,2104],{},[14,2101,2103],{"href":2102},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fformat-chart-axes-with-openpyxl\u002F","Format Chart Axes with openpyxl"," — axis scaling and number formats.",[1980,2106,2107,2111],{},[14,2108,2110],{"href":2109},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fcalculate-moving-averages-with-pandas-rolling\u002F","Calculate Moving Averages with pandas rolling"," — the usual companion series to a price chart.",[2113,2114,2115],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}",{"title":30,"searchDepth":407,"depth":407,"links":2117},[2118,2119,2120,2121,2122,2123,2124,2125,2126,2127,2128],{"id":22,"depth":407,"text":23},{"id":377,"depth":407,"text":378},{"id":533,"depth":407,"text":534},{"id":943,"depth":407,"text":944},{"id":1196,"depth":407,"text":1197},{"id":1481,"depth":407,"text":1482},{"id":1650,"depth":407,"text":1651},{"id":1974,"depth":407,"text":1975},{"id":2019,"depth":407,"text":2020},{"id":2042,"depth":407,"text":2043},{"id":2081,"depth":407,"text":2082},"2026-09-29","Draw an open-high-low-close candlestick chart in Excel from Python: the column order Excel requires, hiding the series lines, high-low lines, up and down bars in your own colours, a value axis that does not start at zero, trading days without weekend gaps, and a volume chart underneath.","md",[2133,2135,2137,2139],{"q":2048,"a":2134},"Use openpyxl's StockChart with four series in the order Open, High, Low, Close, set each series' line to noFill, and set chart.hiLowLines = ChartLines() and chart.upDownBars = UpDownBars(). Add the dates as categories.",{"q":2054,"a":2136},"The series lines are still drawn. Set line.noFill = True on each series' graphicalProperties; the candles come from the high-low lines and up-down bars.",{"q":2067,"a":2138},"Pass upBars and downBars to UpDownBars, each a ChartLines whose spPr is a GraphicalProperties with the fill colour you want, such as GraphicalProperties(solidFill=\"0F9488\").",{"q":2077,"a":2140},"Use a text category axis, which is the stock chart's default in openpyxl: it gives one slot per row, so only the dates in the data appear. A date axis spaces points by calendar date and leaves weekend gaps.","create a stock chart with openpyxl",null,{"breadcrumb":2144},[2145,2148,2151],{"name":2146,"item":2147},"Home","\u002F",{"name":2149,"item":2150},"Formatting and Charting Excel Reports with Python","\u002Fformatting-and-charting-excel-reports-with-python\u002F",{"name":17,"item":16},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fcreate-a-stock-chart-with-openpyxl",{"title":2154,"description":2155},"Excel Candlestick (OHLC) Stock Chart with openpyxl","Create an Excel stock chart with openpyxl StockChart: Open, High, Low, Close series in order, line.noFill, hiLowLines, UpDownBars with custom colours, y-axis minimum, a text axis for trading days and a matching volume bar chart.","create-a-stock-chart-with-openpyxl","formatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fcreate-a-stock-chart-with-openpyxl\u002Findex",[2159,2160],"charts-and-images","openpyxl","how-to","tqgrnj18jcNzUppoJ2ao9H-dGOz2ND5uSyQed18KaJQ",[2164,2168],{"title":2165,"path":2166,"stem":2167,"children":-1},"Create a Step Chart in Excel with Python","\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fcreate-a-step-chart-in-excel-with-python","formatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fcreate-a-step-chart-in-excel-with-python\u002Findex",{"title":2169,"path":2170,"stem":2171,"children":-1},"Create a Waffle or Progress Chart in Excel","\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fcreate-a-waffle-or-progress-chart-in-excel","formatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fcreate-a-waffle-or-progress-chart-in-excel\u002Findex",[2173,2175],{"path":2174,"title":17},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl",{"path":2176,"title":2149},"\u002Fformatting-and-charting-excel-reports-with-python",[],[2179,2182,2185,2188,2191,2194],{"path":2180,"title":2181,"kind":2161},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fbuild-a-dashboard-sheet-with-charts-from-multiple-tabs","Build a Dashboard Sheet with Charts from Multiple Tabs",{"path":2183,"title":2184,"kind":2161},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fbuild-a-rolling-12-month-chart-on-an-excel-dashboard","Build a Rolling 12-Month Chart on an Excel Dashboard",{"path":2186,"title":2187,"kind":2161},"\u002Fautomating-reporting-workflows\u002Fgenerating-excel-reports-from-templates\u002Fkeep-charts-and-images-when-filling-an-excel-template","Keep Charts and Images When Filling an Excel Template",{"path":2189,"title":2190,"kind":2161},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fadd-a-chart-to-an-excel-file-with-xlsxwriter","Add a Chart to an Excel File with xlsxwriter",{"path":2192,"title":2193,"kind":2161},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fadd-sparklines-to-an-excel-report-with-xlsxwriter","Add Sparklines to an Excel Report with xlsxwriter",{"path":2195,"title":2196,"kind":2161},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fbuild-a-waterfall-chart-in-excel-with-python","Build a Waterfall Chart in Excel with Python",1790972111192]