{"id":"a751659e-0696-4990-8053-5792b98b2262","shortId":"SxEts7","kind":"skill","title":"generate-asset-price-chart","tagline":"Generate candlestick price charts for any asset from existing OHLC data, without handling data fetching.","description":"# Generate Asset Price Chart (from OHLC data)\n\nRender a candlestick chart image from preloaded OHLC candles. This skill focuses only on chart generation logic (no API calls).\n\n## When to use\n- You already have OHLC candles and need a visual chart\n- You want to generate PNG charts in backend jobs or bots\n- You need a reusable chart renderer for any asset/timeframe\n\n## Required tools / APIs\n- No external API required\n- Node.js option: `canvas`\n- Python option: `matplotlib`\n\nInstall:\n\n```bash\n# Node.js\nnpm install canvas\n\n# Python\npython -m pip install matplotlib\n```\n\nInput OHLC format expected by both examples:\n- Array of rows: `[timestamp, open, high, low, close]`\n- `timestamp` can be unix ms or any x-axis label value\n\n## Skills\n\n### generate_candlestick_chart_with_nodejs\n\n```javascript\nimport { createCanvas } from \"canvas\";\nimport { writeFile } from \"node:fs/promises\";\n\nfunction validateOhlc(data) {\n  if (!Array.isArray(data) || data.length === 0) {\n    throw new Error(\"OHLC data must be a non-empty array\");\n  }\n\n  data.forEach((row, index) => {\n    if (!Array.isArray(row) || row.length < 5) {\n      throw new Error(`Invalid row at index ${index}. Expected [timestamp, open, high, low, close]`);\n    }\n\n    const [, open, high, low, close] = row;\n    [open, high, low, close].forEach((v) => {\n      if (!Number.isFinite(v)) {\n        throw new Error(`Non-numeric OHLC value at row ${index}`);\n      }\n    });\n  });\n}\n\nfunction generateCandlestickChart(ohlcData, options = {}) {\n  validateOhlc(ohlcData);\n\n  const width = options.width ?? 1200;\n  const height = options.height ?? 600;\n  const padding = options.padding ?? 60;\n\n  const canvas = createCanvas(width, height);\n  const ctx = canvas.getContext(\"2d\");\n\n  // Background\n  ctx.fillStyle = \"#1e1e2e\";\n  ctx.fillRect(0, 0, width, height);\n\n  const chartWidth = width - padding * 2;\n  const chartHeight = height - padding * 2;\n\n  const highs = ohlcData.map((d) => d[2]);\n  const lows = ohlcData.map((d) => d[3]);\n\n  const minPrice = Math.min(...lows);\n  const maxPrice = Math.max(...highs);\n  const priceRange = Math.max(maxPrice - minPrice, 1e-9);\n\n  const xStep = chartWidth / Math.max(ohlcData.length, 1);\n  const yScale = chartHeight / priceRange;\n\n  // Grid\n  ctx.strokeStyle = \"#333\";\n  ctx.lineWidth = 1;\n  for (let i = 0; i <= 5; i++) {\n    const y = padding + (chartHeight / 5) * i;\n    ctx.beginPath();\n    ctx.moveTo(padding, y);\n    ctx.lineTo(width - padding, y);\n    ctx.stroke();\n  }\n\n  // Candles\n  ohlcData.forEach(([, open, high, low, close], index) => {\n    const x = padding + index * xStep + xStep / 2;\n\n    const highY = height - padding - (high - minPrice) * yScale;\n    const lowY = height - padding - (low - minPrice) * yScale;\n    const openY = height - padding - (open - minPrice) * yScale;\n    const closeY = height - padding - (close - minPrice) * yScale;\n\n    const bullish = close >= open;\n    ctx.strokeStyle = bullish ? \"#4caf50\" : \"#f44336\";\n    ctx.fillStyle = ctx.strokeStyle;\n\n    // Wick\n    ctx.beginPath();\n    ctx.moveTo(x, highY);\n    ctx.lineTo(x, lowY);\n    ctx.stroke();\n\n    // Body\n    const bodyTop = Math.min(openY, closeY);\n    const bodyHeight = Math.max(Math.abs(openY - closeY), 2); // keep flat candles visible\n    const bodyWidth = Math.max(xStep * 0.6, 1);\n    ctx.fillRect(x - bodyWidth / 2, bodyTop, bodyWidth, bodyHeight);\n  });\n\n  return canvas.toBuffer(\"image/png\");\n}\n\n// Example usage with existing OHLC array\nconst sample = [\n  [1700000000000, 100, 110, 95, 108],\n  [1700000600000, 108, 112, 104, 106],\n  [1700001200000, 106, 115, 103, 113],\n  [1700001800000, 113, 118, 109, 111],\n  [1700002400000, 111, 119, 110, 117],\n];\n\nconst image = generateCandlestickChart(sample, { width: 1200, height: 600 });\nawait writeFile(\"candlestick.png\", image);\nconsole.log(\"Saved: candlestick.png\");\n```\n\n## Agent prompt\n```text\nYou are generating a candlestick chart image from existing OHLC data only.\nDo not fetch market data and do not add API logic.\n\nInput format is an array of [timestamp, open, high, low, close].\nUse either Node.js (canvas) or Python (matplotlib) to render candles with:\n- dark background,\n- simple horizontal grid,\n- green bullish candles,\n- red bearish candles,\n- visible wick and body.\n\nReturn:\n1) the code used,\n2) output filename,\n3) a short validation note (e.g., candle count rendered).\n```\n\n## Best practices\n- Validate OHLC shape before rendering\n- Ensure candle body has a minimum visible height for flat candles\n- Keep rendering pure: chart function accepts data and returns/saves image\n- Separate fetching/ETL from visualization\n\n## Troubleshooting\n- `Module not found: canvas` → run `npm install canvas`\n- Python import error for matplotlib → run `python -m pip install matplotlib`\n- Blank/flat chart → verify that OHLC values are numeric and vary across candles\n- Inverted y-axis feeling → confirm conversion formula maps higher prices upward\n\n## See also\n- [trading-indicators-from-price-data.md](trading-indicators-from-price-data.md) — derive indicators before plotting\n- [get-crypto-price.md](get-crypto-price.md) — fetch data separately, then pass OHLC into this chart skill","tags":["generate","asset","price","chart","open","skills","besoeasy","agent-skills","ai-agents","claude-code","clawdbot","clawdbot-skill"],"capabilities":["skill","source-besoeasy","skill-generate-asset-price-chart","topic-agent-skills","topic-ai-agents","topic-claude-code","topic-clawdbot","topic-clawdbot-skill","topic-llm-tools","topic-mcp-server","topic-openai","topic-openclaw","topic-vibe-coding","topic-vibecoding"],"categories":["open-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/besoeasy/open-skills/generate-asset-price-chart","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add besoeasy/open-skills","source_repo":"https://github.com/besoeasy/open-skills","install_from":"skills.sh"}},"qualityScore":"0.505","qualityRationale":"deterministic score 0.51 from registry signals: · indexed on github topic:agent-skills · 111 github stars · SKILL.md body (5,137 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-02T12:55:03.696Z","embedding":null,"createdAt":"2026-04-18T22:10:44.187Z","updatedAt":"2026-05-02T12:55:03.696Z","lastSeenAt":"2026-05-02T12:55:03.696Z","tsv":"'0':156,249,250,307 '0.6':408 '1':294,303,409,532 '100':429 '103':441 '104':436 '106':437,439 '108':432,434 '109':446 '110':430,451 '111':447,449 '112':435 '113':442,444 '115':440 '117':452 '118':445 '119':450 '1200':226,458 '1700000000000':428 '1700000600000':433 '1700001200000':438 '1700001800000':443 '1700002400000':448 '1e-9':288 '1e1':246 '2':257,262,268,339,399,413,536 '2d':243 '3':274,539 '333':301 '4caf50':374 '5':176,309,315 '60':234 '600':230,460 '95':431 'accept':571 'across':610 'add':491 'agent':468 'alreadi':52 'also':625 'api':46,83,86,492 'array':113,168,425,498 'array.isarray':153,173 'asset':3,12,22 'asset/timeframe':80 'await':461 'axi':130,615 'backend':68 'background':244,517 'bash':95 'bearish':525 'best':548 'blank/flat':600 'bodi':387,530,557 'bodyheight':394,416 'bodytop':389,414 'bodywidth':405,412,415 'bot':71 'bullish':369,373,522 'call':47 'candl':36,55,326,402,514,523,526,545,556,565,611 'candlestick':7,30,135,475 'candlestick.png':463,467 'canva':90,99,143,236,508,584,588 'canvas.getcontext':242 'canvas.tobuffer':418 'chart':5,9,24,31,42,60,66,76,136,476,569,601,642 'chartheight':259,297,314 'chartwidth':254,291 'close':120,190,195,200,331,365,370,504 'closey':362,392,398 'code':534 'confirm':617 'console.log':465 'const':191,223,227,231,235,240,253,258,263,269,275,279,283,289,295,311,333,340,347,354,361,368,388,393,404,426,453 'convers':618 'count':546 'createcanva':141,237 'ctx':241 'ctx.beginpath':317,379 'ctx.fillrect':248,410 'ctx.fillstyle':245,376 'ctx.lineto':321,383 'ctx.linewidth':302 'ctx.moveto':318,380 'ctx.stroke':325,386 'ctx.strokestyle':300,372,377 'd':266,267,272,273 'dark':516 'data':16,19,27,151,154,161,481,487,572,635 'data.foreach':169 'data.length':155 'deriv':628 'e.g':544 'e2e':247 'either':506 'empti':167 'ensur':555 'error':159,179,208,591 'exampl':112,420 'exist':14,423,479 'expect':109,185 'extern':85 'f44336':375 'feel':616 'fetch':20,485,634 'fetching/etl':577 'filenam':538 'flat':401,564 'focus':39 'foreach':201 'format':108,495 'formula':619 'found':583 'fs/promises':148 'function':149,217,570 'generat':2,6,21,43,64,134,473 'generate-asset-price-chart':1 'generatecandlestickchart':218,455 'get-crypto-price.md':632,633 'green':521 'grid':299,520 'handl':18 'height':228,239,252,260,342,349,356,363,459,562 'high':118,188,193,198,264,282,329,344,502 'higher':621 'highi':341,382 'horizont':519 'imag':32,454,464,477,575 'image/png':419 'import':140,144,590 'index':171,183,184,216,332,336 'indic':629 'input':106,494 'instal':94,98,104,587,598 'invalid':180 'invert':612 'javascript':139 'job':69 'keep':400,566 'label':131 'let':305 'logic':44,493 'low':119,189,194,199,270,278,330,351,503 'lowi':348,385 'm':102,596 'map':620 'market':486 'math.abs':396 'math.max':281,285,292,395,406 'math.min':277,390 'matplotlib':93,105,511,593,599 'maxpric':280,286 'minimum':560 'minpric':276,287,345,352,359,366 'modul':581 'ms':125 'must':162 'need':57,73 'new':158,178,207 'node':147 'node.js':88,96,507 'nodej':138 'non':166,210 'non-empti':165 'non-numer':209 'note':543 'npm':97,586 'number.isfinite':204 'numer':211,607 'ohlc':15,26,35,54,107,160,212,424,480,551,604,639 'ohlcdata':219,222 'ohlcdata.foreach':327 'ohlcdata.length':293 'ohlcdata.map':265,271 'open':117,187,192,197,328,358,371,501 'openi':355,391,397 'option':89,92,220 'options.height':229 'options.padding':233 'options.width':225 'output':537 'pad':232,256,261,313,319,323,335,343,350,357,364 'pass':638 'pip':103,597 'plot':631 'png':65 'practic':549 'preload':34 'price':4,8,23,622 'pricerang':284,298 'prompt':469 'pure':568 'python':91,100,101,510,589,595 'red':524 'render':28,77,513,547,554,567 'requir':81,87 'return':417,531 'returns/saves':574 'reusabl':75 'row':115,170,174,181,196,215 'row.length':175 'run':585,594 'sampl':427,456 'save':466 'see':624 'separ':576,636 'shape':552 'short':541 'simpl':518 'skill':38,133,643 'skill-generate-asset-price-chart' 'source-besoeasy' 'text':470 'throw':157,177,206 'timestamp':116,121,186,500 'tool':82 'topic-agent-skills' 'topic-ai-agents' 'topic-claude-code' 'topic-clawdbot' 'topic-clawdbot-skill' 'topic-llm-tools' 'topic-mcp-server' 'topic-openai' 'topic-openclaw' 'topic-vibe-coding' 'topic-vibecoding' 'trading-indicators-from-price-data.md':626,627 'troubleshoot':580 'unix':124 'upward':623 'usag':421 'use':50,505,535 'v':202,205 'valid':542,550 'validateohlc':150,221 'valu':132,213,605 'vari':609 'verifi':602 'visibl':403,527,561 'visual':59,579 'want':62 'wick':378,528 'width':224,238,251,255,322,457 'without':17 'writefil':145,462 'x':129,334,381,384,411 'x-axi':128 'xstep':290,337,338,407 'y':312,320,324,614 'y-axi':613 'yscale':296,346,353,360,367","prices":[{"id":"cd0e80c4-be16-4fa7-8bf9-ea51154701a3","listingId":"a751659e-0696-4990-8053-5792b98b2262","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"besoeasy","category":"open-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T22:10:44.187Z"}],"sources":[{"listingId":"a751659e-0696-4990-8053-5792b98b2262","source":"github","sourceId":"besoeasy/open-skills/generate-asset-price-chart","sourceUrl":"https://github.com/besoeasy/open-skills/tree/main/skills/generate-asset-price-chart","isPrimary":false,"firstSeenAt":"2026-04-18T22:10:44.187Z","lastSeenAt":"2026-05-02T12:55:03.696Z"}],"details":{"listingId":"a751659e-0696-4990-8053-5792b98b2262","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"besoeasy","slug":"generate-asset-price-chart","github":{"repo":"besoeasy/open-skills","stars":111,"topics":["agent-skills","ai","ai-agents","claude-code","clawdbot","clawdbot-skill","llm-tools","mcp-server","openai","openclaw","vibe-coding","vibecoding"],"license":null,"html_url":"https://github.com/besoeasy/open-skills","pushed_at":"2026-03-31T13:05:30Z","description":"Battle-tested skill library for AI agents. Save 98% of API costs with ready-to-use code for crypto, PDFs, search, web scraping & more. No trial-and-error, no expensive APIs.","skill_md_sha":"ff13dd95dcd599d2cb60c1a726bd11d85b652fa8","skill_md_path":"skills/generate-asset-price-chart/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/besoeasy/open-skills/tree/main/skills/generate-asset-price-chart"},"layout":"multi","source":"github","category":"open-skills","frontmatter":{"name":"generate-asset-price-chart","description":"Generate candlestick price charts for any asset from existing OHLC data, without handling data fetching."},"skills_sh_url":"https://skills.sh/besoeasy/open-skills/generate-asset-price-chart"},"updatedAt":"2026-05-02T12:55:03.696Z"}}