{"id":723,"date":"2026-03-06T17:28:52","date_gmt":"2026-03-06T17:28:52","guid":{"rendered":"https:\/\/web3fuel.io\/article\/?p=723"},"modified":"2026-03-06T17:28:53","modified_gmt":"2026-03-06T17:28:53","slug":"ai-system-python","status":"publish","type":"post","link":"https:\/\/web3fuel.io\/article\/ai-system-python\/","title":{"rendered":"How to Build a Self-Optimizing AI Trading System In Python"},"content":{"rendered":"<div class=\"et_pb_section_0 et_pb_section et_section_regular et_block_section\">\n<div class=\"et_pb_row_0 et_pb_row et_flex_row preset--group--divi-row--divi-sizing--w5u0x3y1pz\">\n<div class=\"et_pb_column_0 et_pb_column et-last-child et_flex_column et_pb_css_mix_blend_mode_passthrough et_flex_column_24_24 et_flex_column_24_24_tablet et_flex_column_24_24_phone\">\n<div class=\"et_pb_text_0 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h1 class=\"text-text-100 mt-3 -mb-1 text-[1.375rem] font-bold\">How to Build a Self-Optimizing AI Trading System in Python<\/h1>\n<\/div><\/div>\n\n<div class=\"et_pb_text_1 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><p><em>Stay up-to-date with macroeconomic news &amp; investments without spending two hours reading Bloomberg every morning. Nothing here is financial advice.<\/em><\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_1 et_pb_row et_flex_row preset--group--divi-row--divi-sizing--w5u0x3y1pz\">\n<div class=\"et_pb_column_1 et_pb_column et-last-child et_flex_column et_pb_css_mix_blend_mode_passthrough et_flex_column_24_24 et_flex_column_24_24_tablet et_flex_column_24_24_phone\">\n<div class=\"et_pb_post_title_0 et_pb_post_title et_pb_bg_layout_light et_clickable et_pb_module et_block_module\"><div class=\"et_pb_title_container\"><p class=\"et_pb_title_meta_container\">by <span class=\"author vcard\"><a href=\"https:\/\/web3fuel.io\/article\/author\/admin_546\/\" title=\"Posts by Alex G.\">Alex G.<\/a><\/span> | <span class=\"published\">Mar 6, 2026<\/span><\/p><\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_2 et_pb_row et_flex_row preset--group--divi-row--divi-sizing--w5u0x3y1pz\">\n<div class=\"et_pb_column_2 et_pb_column et-last-child et_flex_column et_pb_css_mix_blend_mode_passthrough et_flex_column_24_24 et_flex_column_24_24_tablet et_flex_column_24_24_phone\">\n<div class=\"et_pb_text_2 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h2><strong><span style=\"color: #00ffff;\">\/\/ <\/span>Summary<\/strong><\/h2>\n<\/div><\/div>\n\n<div class=\"et_pb_text_3 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">What started as a simple script to summarize financial headlines evolved into a multi-agent pipeline with five sequential Claude API calls, a self-calibrating feedback loop, live brokerage integration, and a unified dashboard.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">This system reads macro news, derives a structured trade idea, tracks whether that idea was right, and uses that track record to calibrate its own future recommendations.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">The feedback loop is the secret sauce that separates this from a prompt wrapper with a Discord webhook.<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_image_0 et_pb_image et_pb_module et_block_module\"><span class=\"et_pb_image_wrap\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/web3fuel.io\/article\/wp-content\/uploads\/2026\/02\/News-Analysis-Architecture.png\" alt=\"News Analysis Architecture\" title=\"News Analysis Architecture\" width=\"700\" height=\"900\" srcset=\"https:\/\/web3fuel.io\/article\/wp-content\/uploads\/2026\/02\/News-Analysis-Architecture.png 700w, https:\/\/web3fuel.io\/article\/wp-content\/uploads\/2026\/02\/News-Analysis-Architecture-480x617.png 480w\" sizes=\"(min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) 700px, 100vw\" class=\"wp-image-726\" \/><\/span><\/div>\n\n<div class=\"et_pb_text_4 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">The news ingestion layer pulls the top macro stories of the day and structures them as JSON. The indicators layer fetches live market snapshots from yfinance. The Claude analysis pipeline runs three sequential API calls, each with a specific reasoning task. The storage layer is MySQL, with five core tables. The notification layer is Discord webhooks. And the feedback loop is what ties it all together: trade ideas get tracked automatically, outcomes get resolved against live prices, and accuracy statistics get fed back into the next Claude prompt.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_3 et_pb_row et_flex_row preset--group--divi-row--divi-sizing--w5u0x3y1pz\">\n<div class=\"et_pb_column_3 et_pb_column et-last-child et_flex_column et_pb_css_mix_blend_mode_passthrough et_flex_column_24_24 et_flex_column_24_24_tablet et_flex_column_24_24_phone\">\n<div class=\"et_pb_code_0 et_pb_code et_pb_module\"><div class=\"et_pb_code_inner\"><div id=\"table-of-contents\" style=\"background: rgba(173,173,173,0.05); padding: 10px 20px 0px 10px; border-radius: 5px; margin: 10px 0;\">\n  <h3 style=\"margin-top: 0; text-align: center; text-decoration: underline; background: linear-gradient(90deg, #ff0000, #ff7f00, #ffff00); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; cursor: pointer; display: flex; align-items: center; justify-content: center; position: relative; font-size: 24px; font-weight: 750\" id=\"toc-header\">\n    Table of Contents\n    <span id=\"toc-arrow\" style=\"position: absolute; right: 0; transition: transform 0.3s; -webkit-text-fill-color: initial; background: none; color: white;\">\u25bc<\/span>\n  <\/h3>\n  <ul id=\"toc-list\" style=\"list-style: none; padding-left: 0; display: none;\"><\/ul>\n<\/div>\n\n<script>\ndocument.addEventListener('DOMContentLoaded', function() {\n  const tocList = document.getElementById('toc-list');\n  const tocHeader = document.getElementById('toc-header');\n  const tocArrow = document.getElementById('toc-arrow');\n  \n  \/\/ Toggle collapse functionality\n  tocHeader.addEventListener('click', function() {\n    if (tocList.style.display === 'none') {\n      tocList.style.display = 'block';\n      tocArrow.style.transform = 'rotate(180deg)';\n    } else {\n      tocList.style.display = 'none';\n      tocArrow.style.transform = 'rotate(0deg)';\n    }\n  });\n  \n  \/\/ Target headings in both post content AND Divi text modules\n  const headings = document.querySelectorAll('.et_pb_text_inner h2, .et_pb_text_inner h3, .et_pb_text_inner h4, .et_pb_post_content h2, .et_pb_post_content h3, .et_pb_post_content h4');\n  \n  if (headings.length === 0) {\n    document.getElementById('table-of-contents').style.display = 'none';\n    return;\n  }\n  \n  headings.forEach((heading, index) => {\n    \/\/ Add ID to heading if it doesn't have one\n    if (!heading.id) {\n      heading.id = 'heading-' + index;\n    }\n    \n    \/\/ Create TOC item\n    const li = document.createElement('li');\n    li.style.marginBottom = '8px';\n    \n    \/\/ Indent H3s and H4s\n    if (heading.tagName === 'H3') {\n      li.style.paddingLeft = '20px';\n      li.style.fontSize = '0.95em';\n    }\n    if (heading.tagName === 'H4') {\n      li.style.paddingLeft = '40px';\n      li.style.fontSize = '0.9em';\n    }\n    \n    \/\/ Create link\n    const link = document.createElement('a');\n    link.href = '#' + heading.id;\n    link.textContent = heading.textContent;\n    link.style.textDecoration = 'none';\n    link.style.color = '#0066cc';\n    link.style.transition = 'color 0.2s';\n    \n    \/\/ Hover effect\n    link.addEventListener('mouseenter', function() {\n      this.style.color = '#0099ff';\n      this.style.textDecoration = 'underline';\n    });\n    link.addEventListener('mouseleave', function() {\n      this.style.color = '#0066cc';\n      this.style.textDecoration = 'none';\n    });\n    \n    \/\/ Smooth scroll with padding above heading\n    link.addEventListener('click', function(e) {\n      e.preventDefault();\n      const offset = 120; \/\/ Increased from 100 to add more space above the heading\n      const elementPosition = heading.getBoundingClientRect().top + window.pageYOffset;\n      window.scrollTo({ top: elementPosition - offset, behavior: 'smooth' });\n    });\n    \n    li.appendChild(link);\n    tocList.appendChild(li);\n  });\n});\n<\/script><\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_4 et_pb_row et_flex_row preset--group--divi-row--divi-sizing--w5u0x3y1pz\">\n<div class=\"et_pb_column_4 et_pb_column et-last-child et_flex_column et_pb_css_mix_blend_mode_passthrough et_flex_column_24_24 et_flex_column_24_24_tablet et_flex_column_24_24_phone\">\n<div class=\"et_pb_text_5 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h2><strong><span style=\"color: #00ffff;\">\/\/\u00a0<\/span><\/strong>News Ingestion: Two Sources, One Format<\/h2>\n<\/div><\/div>\n\n<div class=\"et_pb_text_6 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">The ingestion layer has two modes that produce identical outputs:<\/p>\n<h3 class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">Comet Browser<\/h3>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">The primary source is Comet, a browser-based Perplexity AI agent I can run manually. It scans financial news and writes a structured JSON file with the top five macro stories. Each story includes a headline, an impact score from one to ten, a macro theme like \"Fed hawkish pivot\" or \"energy supply shock,\" a directional bias, and a list of affected sectors and key instruments.<\/p>\n<h3 class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">Perplexity API<\/h3>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">The fallback is the Perplexity API, using their Sonar model at roughly five cents per scan. When a cron job runs and the JSON file is older than sixteen hours, the system automatically triggers the Perplexity fallback. The Perplexity prompt is written to behave like a macro analyst: it is instructed to identify the top market-moving stories across Fed and ECB policy, inflation, PMI, geopolitics, energy, and credit, and to cross-check the headline narrative against actual recent price action before scoring impact.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">The reason for two sources is cost and reliability. Comet is free, but manual. Perplexity API costs money, but runs unattended. The sixteen-hour staleness window means I can run Comet in the morning when I am at my desk and let Perplexity cover the automated runs.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">The high-impact stories, anything above a configurable impact threshold, also get queued to perform a more detailed research pass on each of those stories, looking at historical precedent, second-order effects, key upcoming dates, and potential entry and exit points. Those research summaries get stored and injected into the next Claude analysis call. It is the closest thing to a research analyst in the pipeline.<\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_5 et_pb_row et_flex_row preset--group--divi-row--divi-sizing--w5u0x3y1pz\">\n<div class=\"et_pb_column_5 et_pb_column et-last-child et_flex_column et_pb_css_mix_blend_mode_passthrough et_flex_column_24_24 et_flex_column_24_24_tablet et_flex_column_24_24_phone\">\n<div class=\"et_pb_text_7 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h2><strong><span style=\"color: #00ffff;\">\/\/\u00a0<\/span><\/strong>The Five-Call Claude Reasoning Pipeline<\/h2>\n<\/div><\/div>\n\n<div class=\"et_pb_text_8 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">This is the most architecturally interesting part of the system.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">The reason for separating into three calls is because when you mix different reasoning tasks in a single prompt, the model anchors to information it should not have yet.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">For example, if Claude knows that XLE is trading at $89.50 while it is trying to form a macro directional conviction, it anchors to that price. The reasoning gets contaminated before it even starts. Separating the calls forces clean cognitive boundaries.<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_text_9 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h3 class=\"text-text-100 mt-2 -mb-1 text-base font-bold\">Call One: Pure Macro Reasoning<\/h3>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">The first call receives the top macro stories, the deep-dive research summaries for high-impact items, the current market indicators, and Claude's own historical accuracy statistics from the feedback loop.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">It produces a market regime assessment, a sector prediction, one or two ticker recommendations, a directional thesis, a confidence score from zero to five, and a setup grade from A-plus down to C.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">Critically, there are no prices in this call. The question being asked is purely: given what is happening in macro, what sector should move and in which direction, and how confident are we? Letting the model answer that without price anchoring produces cleaner directional conviction.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">The grading system is worth explaining separately because it drives most of the downstream logic. Confidence and quality are related but not identical. A confidence score of four means Claude thinks the trade idea is well-supported. A setup grade of A-plus means the conditions are exceptional: the catalyst is unambiguous, the macro regime aligns with the thesis, the sector has not yet priced in the move, and the risk-to-reward profile is clean. An A-plus setup is rare by design. Most scans produce B or C grades, and that is intentional.<\/p>\n<h3 class=\"text-text-100 mt-2 -mb-1 text-base font-bold\">Call Two: Price Level Setting<\/h3>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">The second call receives the output from call one plus live prices fetched via yfinance. Its only job is to calculate specific entry, target, and stop-loss levels for each recommended ticker.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">The prompt constrains it meaningfully. Targets for sector ETFs should represent a five to fifteen percent move. Stop-losses should be placed at logical technical support levels, not at arbitrary percentage offsets. The minimum risk-to-reward ratio required is two-to-one. If that ratio cannot be achieved given current prices, the system notes it.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">This is a genuinely different cognitive task from call one. The first call is asking what will happen. The second call is asking, given what we believe will happen and given where prices are right now, where exactly do we put our levels. Mixing these produces worse output on both dimensions. The first call loses directional conviction because it is thinking about price levels. The second call loses precision because it is re-litigating the macro thesis.<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_code_1 et_pb_code et_pb_module\"><div class=\"et_pb_code_inner\"><div class=\"w3f-code-block\"><div class=\"w3f-code-title\">Price Correction Prompt<\/div><div class=\"w3f-code-lang-badge\">PYTHON<\/div><pre class=\"\"><code class=\"language-python\">def _build_price_correction_prompt(result, prices):\n    return (\n        &quot;You are setting entry, target, and stop-loss levels &quot;\n        &quot;for a swing trade.\\n\\n&quot;\n        f&quot;Direction: {direction.upper()}\\n&quot;\n        f&quot;Current prices (LIVE from market data):\\n&quot;\n        f&quot;{price_lines}\\n&quot;  # e.g. &quot;XLE: $89.50 | OXY: $52.10&quot;\n        &quot;RULES:\\n&quot;\n        &quot;- Target: 5-15% move for sector ETFs, &quot;\n        &quot;8-20% for individual stocks.\\n&quot;\n        &quot;- Stop: logical support\/resistance level, &quot;\n        &quot;typically 3-7% from entry.\\n&quot;\n        &quot;- Risk\/reward ratio should be at least 2:1.\\n&quot;\n    )<\/code><\/pre><\/div><\/div><\/div>\n\n<div class=\"et_pb_text_10 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h3 class=\"text-text-100 mt-2 -mb-1 text-base font-bold\">Call Three: Vehicle Selection<\/h3>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">The third call receives the outputs from both previous calls plus, when available, a live options chain pulled from the Questrade API. Its job is to recommend whether the trade should be expressed as a stock position, an options play, or a Polymarket prediction market bet.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">This matters because the same directional thesis has very different risk-to-reward profiles depending on how it is expressed. A high-conviction two-week thesis on energy sector upside looks completely different as a position in XLE versus a near-money call option expiring in three weeks. The options chain data lets Claude reason about implied volatility, strike selection, and premium cost relative to the expected move.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">The Polymarket module is an interesting edge case. Some macro stories map cleanly onto open prediction market questions with binary outcomes. \"Will the Fed cut rates at the March meeting?\" is the kind of question where a strong macro thesis and a mispriced binary market can create a completely different risk profile than any equity trade. The third call flags these when it finds a match.<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_text_11 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h3 class=\"text-text-100 mt-2 -mb-1 text-base font-bold\">Call Three &amp; Four: Cross-Database Selection<\/h3>\n<div>\n<div><span>These are the most architecturally interesting calls because they bridge two separate MySQL databases.<\/span><\/div>\n<div><span><\/span><\/div>\n<div><span>Call 3 extracts 3-5 search keywords from the macro narrative.\u00a0<\/span><span>Those keywords query the separate <\/span><span>`polymarket_monitor`<\/span><span> database for active prediction markets with odds between 5-95%<\/span><\/div>\n<\/div>\n<\/div><\/div>\n\n<div class=\"et_pb_code_2 et_pb_code et_pb_module\"><div class=\"et_pb_code_inner\"><div class=\"w3f-code-block\"><div class=\"w3f-code-title\">Extract keywords for search<\/div><div class=\"w3f-code-lang-badge\">PYTHON<\/div><pre class=\"\"><code class=\"language-python\"># Returns: [&quot;Fed rate cut&quot;, &quot;March FOMC&quot;, &quot;interest rates&quot;]\nkw_msg = client.messages.create(\n    model=CLAUDE_MODEL, max_tokens=200, ...\n)<\/code><\/pre><\/div><\/div><\/div>\n\n<div class=\"et_pb_code_3 et_pb_code et_pb_module\"><div class=\"et_pb_code_inner\"><div class=\"w3f-code-block\"><div class=\"w3f-code-title\">Cross-database query against the Polymarket monitor's tables<\/div><div class=\"w3f-code-lang-badge\">MYSQL<\/div><pre class=\"\"><code class=\"language-mySQL\">query = &quot;&quot;&quot;\n    SELECT m.question, ms.yes_price, m.end_date\n    FROM markets m\n    INNER JOIN market_snapshots ms\n        ON m.market_id = ms.market_id\n    WHERE m.active = TRUE\n      AND ms.yes_price BETWEEN 0.05 AND 0.95\n      AND (m.question LIKE %s OR m.question LIKE %s ...)\n&quot;&quot;&quot;<\/code><\/pre><\/div><\/div><\/div>\n\n<div class=\"et_pb_text_12 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><p><span>Call 4 evaluates whether the top match is mispriced given the macro thesis.\u00a0<\/span><\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_code_4 et_pb_code et_pb_module\"><div class=\"et_pb_code_inner\"><div class=\"w3f-code-block\"><div class=\"w3f-code-title\">Is this market mispriced?<\/div><div class=\"w3f-code-lang-badge\">PYTHON<\/div><pre class=\"\"><code class=\"language-python\"># Returns: {relevant, direction, edge, grade, confidence}\neval_msg = client.messages.create(\n    model=CLAUDE_MODEL, max_tokens=300, ...\n)<\/code><\/pre><\/div><\/div><\/div>\n\n<div class=\"et_pb_text_13 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h3 class=\"text-text-100 mt-2 -mb-1 text-base font-bold\">Call Five: Best Play<\/h3>\n<div>\n<div><span>This call only runs if confidence &gt;= 2<\/span><\/div>\n<div><span><\/span><\/div>\n<div><span>Input: all previous outputs + options chain data from Questrade (if available)<\/span><\/div>\n<div><span><\/span><\/div>\n<div><span>Output: stock vs options vs Polymarket recommendation with reasoning<\/span><\/div>\n<div><span><\/span><\/div>\n<div><span>Why this matters: the same directional thesis has very different risk\/reward profiles depending on vehicle<\/span><\/div>\n<div><span><\/span><\/div>\n<div>\n<div><strong>The grading system:<\/strong><\/div>\n<div><strong><\/strong><\/div>\n<ul>\n<li><span>A+ to C, not just confidence 1-5, because confidence and quality are related but not the same.<\/span><\/li>\n<li>A+ = rare, unambiguous catalyst, regime aligns, sector not yet priced in, clear R:R<\/li>\n<li>The grade feeds into the feedback loop (was A-grade accuracy actually better than B-grade?)<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div><\/div>\n\n<div class=\"et_pb_code_5 et_pb_code et_pb_module\"><div class=\"et_pb_code_inner\"><div class=\"w3f-code-block\"><div class=\"w3f-code-title\">Best Play Prompt<\/div><div class=\"w3f-code-lang-badge\">PYTHON<\/div><pre class=\"\"><code class=\"language-python\">def _build_best_play_prompt(result, prices, options_data):\n    return (\n        &quot;You are recommending the optimal trade vehicle.\\n\\n&quot;\n        f&quot;Confidence: {confidence}\/5, Grade: {grade}\\n&quot;\n        &quot;Choose 'options' when: clear directional catalyst, &quot;\n        &quot;defined timeline...\\n&quot;\n        &quot;Choose 'stock' when: thesis is strong but &quot;\n        &quot;timing uncertain...\\n&quot;\n        &quot;Choose 'polymarket' when: catalyst maps to a &quot;\n        &quot;binary event with mispriced odds.\\n&quot;\n    )<\/code><\/pre><\/div><\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_6 et_pb_row et_flex_row preset--group--divi-row--divi-sizing--w5u0x3y1pz\">\n<div class=\"et_pb_column_6 et_pb_column et-last-child et_flex_column et_pb_css_mix_blend_mode_passthrough et_flex_column_24_24 et_flex_column_24_24_tablet et_flex_column_24_24_phone\">\n<div class=\"et_pb_text_14 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h2><strong><span style=\"color: #00ffff;\">\/\/ <\/span><\/strong>The Self-Calibrating Feedback Loop<\/h2>\n<\/div><\/div>\n\n<div class=\"et_pb_text_15 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">This is the part that separates the system from a one-shot prompt wrapper.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">The basic mechanic is straightforward: every trade alert with a confidence score of two or higher automatically creates a row in the <span style=\"color: #ff6600;\"><code class=\"bg-text-200\/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]\">trade_outcomes<\/code><\/span> table. The resolver runs on each pipeline cycle, fetches live prices for all open positions, and checks whether the target or stop has been hit. If neither has been hit within twenty-eight days, the trade is closed at the current price and classified as a win, loss, or breakeven based on a configurable percentage threshold.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">But the interesting part is what gets stored alongside the outcome, and what gets fed back into the next Claude prompt.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">At the time a trade outcome is created, the system snapshots the market regime: VIX level, DXY six-hour percentage change, and SPY six-hour percentage change. It also stores the macro theme, the specific catalyst headline, the sector, and a thesis summary from the original analysis. The risk-to-reward ratio is calculated from the entry, target, and stop prices and stored at creation time.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">At resolution, the regime indicators are snapshotted again. This means you can eventually ask questions like: did the same macro thesis produce different outcomes in high-VIX versus low-VIX environments? The answer to that question is worth more than a flat win rate.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">The outcome model has six resolution states, not just win and loss.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">The resolver checks direction first. For a long trade, if the current price hits the target the trade resolves as a win. If it hits the stop it resolves as a loss. If neither happens within twenty-eight days, the system uses peak tracking to make a more nuanced call. A trade that moved three percent in your favor at its best point before pulling back is not the same as one that went straight against you. The outcome direction_correct captures the first case. The outcome direction_wrong captures the second. Breakeven sits in the middle.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">This distinction matters for the feedback loop. A trade that was right about direction but wrong about exit timing should teach the system something different than a trade that was simply wrong. Binary win and loss collapses that information.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">The peak tracking runs continuously on every resolver check, not just at resolution. This means even if a trade gets stopped out, you have a record of whether it was ever profitable and by how much. That data feeds directly into the stop placement calibration question over time.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">The accuracy stats that get injected into the next Claude prompt look like this once enough data accumulates:<\/p>\n<ul>\n<li class=\"font-claude-response-body break-words whitespace-pre-wrap leading-[1.7]\">Grade A+: direction correct 78% (7\/9), target hit 5\/9, avg peak +8.3%<\/li>\n<li class=\"font-claude-response-body break-words whitespace-pre-wrap leading-[1.7]\">VIX regime: high=3\/4, medium=2\/3, low=1\/2<\/li>\n<li class=\"font-claude-response-body break-words whitespace-pre-wrap leading-[1.7]\">Themes: rates 3\/4, geopolitics 1\/2 Thesis confirmed: 71% (n=7)<\/li>\n<\/ul>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">The prompt tells Claude to use this to calibrate its confidence and grading. Whether it meaningfully adjusts its behavior based on this is still unproven. The feedback loop has been running for less than two weeks at time of writing. That is the honest answer.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">One other piece worth mentioning is thesis validation. Some trades will hit their target for the wrong reasons. A long on energy that wins because the Fed unexpectedly cut rates is not a validation of the energy supply thesis that generated the recommendation. Counting it as a win corrupts the accuracy signal. To address this, the schema includes a thesis_played_out boolean that defaults to null. A CLI command called --review-outcomes surfaces all recently resolved trades where this field has not been set, showing the ticker, outcome, percentage move, catalyst, and thesis summary side by side. Once a week I go through these and mark them. It takes about five minutes and is the most valuable manual input in the system.<\/p>\n<p class=\"font-claude-response-body break-words whitespace-normal leading-[1.7]\">Resolved outcomes are never deleted. The cleanup policy only removes unresolved expired rows. The entire point of building this is to accumulate a training dataset, and deleting it would defeat the purpose.<\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_7 et_pb_row et_flex_row preset--group--divi-row--divi-sizing--w5u0x3y1pz\">\n<div class=\"et_pb_column_7 et_pb_column et-last-child et_flex_column et_pb_css_mix_blend_mode_passthrough et_flex_column_24_24 et_flex_column_24_24_tablet et_flex_column_24_24_phone\">\n<div class=\"et_pb_text_16 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h2><strong><span style=\"color: #00ffff;\">\/\/ <\/span><\/strong><b>Questrade and Polymarket Integrations<\/b><\/h2>\n<\/div><\/div>\n\n<div class=\"et_pb_text_17 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><p>These are optional modules that degrade gracefully if disabled. The core pipeline runs without either of them.<\/p>\n<h3>Questrade<\/h3>\n<p>Questrade is a Canadian discount brokerage with a reasonably well-documented API. The --trade command fetches a live bid\/ask quote, displays an order preview showing entry, target, stop, and total position value, enforces a configurable safety cap that rejects anything above five thousand dollars, and places a limit order. The order ID logs back to the database and a Discord notification confirms execution.<\/p>\n<p>The TSX equivalents layer exists because most of Claude's sector recommendations are US-listed tickers. A curated mapping dictionary of thirty-five entries plus a yfinance probe for anything not in the list handles the translation automatically. XLE becomes XEG.TO. XLF becomes ZEB.TO. Gold via GLD becomes CGL.TO for the CAD-hedged version. This is a small thing that makes the system actually usable for a Canadian brokerage account.<\/p>\n<p>Token refresh is handled automatically. Every Questrade API call is wrapped in a retry function that catches 401 errors, clears the authentication singleton, reinitializes, and retries once before surfacing the failure. In practice this means the integration works across long-running cron sessions without any manual intervention.<\/p>\n<h3>Polymarket<\/h3>\n<p>The Polymarket integration is architecturally interesting because it bridges two separate MySQL databases. Calls three and four in the pipeline handle this together.<\/p>\n<p>Call three extracts three to five search keywords from the macro narrative. Those keywords query the separate polymarket_monitor database for active prediction markets with odds between five and ninety-five percent. Markets near one hundred percent are excluded because there is no meaningful edge in near-certain outcomes. The results are ranked by keyword match count before being passed to Call four.<\/p>\n<p>Call four evaluates whether the top matching market is mispriced given the macro thesis. If the implied odds look off relative to what the macro analysis suggests, it flags a potential bet with an edge estimate and a grade.<\/p>\n<p>The interesting thing about this conversion is that it takes a continuous directional thesis and forces it into a binary probability. A macro view that the Fed is likely to cut rates in March maps onto a Polymarket question trading at forty-five cents as a potential edge, with a completely different risk profile than any equity position. Sometimes that is actually the cleaner trade.<\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_8 et_pb_row et_flex_row preset--group--divi-row--divi-sizing--w5u0x3y1pz\">\n<div class=\"et_pb_column_8 et_pb_column et-last-child et_flex_column et_pb_css_mix_blend_mode_passthrough et_flex_column_24_24 et_flex_column_24_24_tablet et_flex_column_24_24_phone\">\n<div class=\"et_pb_text_18 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h2><strong><span style=\"color: #00ffff;\">\/\/ <\/span><\/strong><b>Discord Notifications<\/b><\/h2>\n<\/div><\/div>\n\n<div class=\"et_pb_image_1 et_pb_image et_pb_module et_block_module\"><span class=\"et_pb_image_wrap\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/web3fuel.io\/article\/wp-content\/uploads\/2026\/03\/Screenshot-2026-03-03-094835.png\" title=\"Screenshot 2026-03-03 094835\" width=\"523\" height=\"578\" srcset=\"https:\/\/web3fuel.io\/article\/wp-content\/uploads\/2026\/03\/Screenshot-2026-03-03-094835.png 523w, https:\/\/web3fuel.io\/article\/wp-content\/uploads\/2026\/03\/Screenshot-2026-03-03-094835-480x530.png 480w\" sizes=\"(min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) 523px, 100vw\" class=\"wp-image-731\" \/><\/span><\/div>\n\n<div class=\"et_pb_text_19 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><p>Alerts are color-coded by conviction level, from grey at confidence two up through blue, yellow, orange, and red at confidence five. Each embed includes the setup grade and confidence in the footer, the directional thesis as the title, and structured fields for ticker, entry, target, stop, timeline, and TSX alternatives.<\/p>\n<p>If a Polymarket match was found it appears as an additional field showing the question, current odds, and the edge estimate. Active position alerts show up in the same embed when today's catalyst affects something already held, with a suggested action of hold, tighten stop, take profit, or close.<\/p>\n<p>An in-memory deduplication cache with a five-minute window prevents the same alert from firing twice when concurrent pipeline runs overlap.<\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_9 et_pb_row et_flex_row preset--group--divi-row--divi-sizing--w5u0x3y1pz\">\n<div class=\"et_pb_column_9 et_pb_column et-last-child et_flex_column et_pb_css_mix_blend_mode_passthrough et_flex_column_24_24 et_flex_column_24_24_tablet et_flex_column_24_24_phone\">\n<div class=\"et_pb_text_20 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h2><strong><span style=\"color: #00ffff;\">\/\/ <\/span><\/strong><b>Honest Limitations and What I Am Watching<\/b><\/h2>\n<\/div><\/div>\n\n<div class=\"et_pb_text_21 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><p>The system has been live for less than two weeks at the time of writing. Everything said above about the feedback loop is architectural, not empirical. I need a minimum of one hundred resolved outcomes before the accuracy statistics mean anything statistically. Right now the system generates signals and tracks them, but whether the feedback loop actually changes Claude's output in useful ways is a hypothesis, not a finding.<\/p>\n<p>The news lag is real. Comet runs manually at scheduled times. A major event at two in the afternoon may not enter the pipeline until the next time I run a scan. This is not a real-time system and should not be treated as one for anything time-sensitive.<\/p>\n<p>Claude's confidence scores are not calibrated probabilities. A confidence of four out of five does not mean an eighty percent win rate. The feedback loop is supposed to discover the actual relationship between those numbers over time, but that relationship is still unknown.<\/p>\n<p>The execution gap between signal and outcome is real and not accounted for anywhere in the system. The pipeline recommends a trade at a specific entry price. Whether you actually execute it, at what size, and with what slippage, is entirely separate from whether the signal was right.<\/p>\n<p>What I am watching over the next ninety days: does A-plus outperform A in practice? Does the system show better direction accuracy in high-VIX environments than low-VIX? Do thesis confirmation rates correlate with actual win rates? Does direction_correct turn out to be a more useful signal than binary win and loss? These questions have real answers. I just do not have the data yet.<\/p>\n<p>&nbsp;<\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_10 et_pb_row et_flex_row preset--group--divi-row--divi-sizing--w5u0x3y1pz\">\n<div class=\"et_pb_column_10 et_pb_column et-last-child et_flex_column et_pb_css_mix_blend_mode_passthrough et_flex_column_24_24 et_flex_column_24_24_tablet et_flex_column_24_24_phone\">\n<div class=\"et_pb_text_22 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h2><strong><span style=\"color: #00ffff;\">\/\/ <\/span><\/strong><b>What I Would Build Differently<\/b><\/h2>\n<\/div><\/div>\n\n<div class=\"et_pb_text_23 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><p>Structured outputs instead of JSON parsing. The current five-call pipeline relies on parsing JSON from Claude's free-form text. It is fragile. A malformed response breaks the pipeline. Anthropic's structured outputs feature would eliminate this and is the first refactor I would make if starting over today.<\/p>\n<p>API ingestion instead of Comet. Comet is free and excellent for prototyping, but it is manual. A production version would ingest from a proper financial news API. The structured JSON format is already defined, so swapping the ingestion layer is a clean refactor without touching anything else.<\/p>\n<p>Vector similarity for story deduplication. The same story can enter the pipeline across multiple scans if it stays in the news cycle for several days. A vector similarity check against recent headlines would prevent redundant analysis and produce cleaner outcome attribution.<\/p>\n<p>A backtesting harness. Before going live I would want to replay several months of historical macro news through the pipeline with frozen indicator snapshots, to get a rough estimate of how quickly the feedback loop converges and whether the grading system shows any predictive signal at all. Running it blind in production is intellectually interesting but not rigorous.<\/p>\n<p>Separate signal from execution. Analysis and order placement currently live in the same codebase. For anything at real scale you want a clean API boundary between the signal service and the execution layer so they can be deployed, debugged, and scaled independently.<\/p>\n<p>Smarter stop placement using peak tracking data. The peak tracking already records whether a trade moved favorably before getting stopped out. Feeding that data back into the price-level prompt could let the system auto-calibrate stop distance over time, rather than relying on Claude's judgment about support levels from a static prompt.<\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_11 et_pb_row et_flex_row preset--group--divi-row--divi-sizing--w5u0x3y1pz\">\n<div class=\"et_pb_column_11 et_pb_column et-last-child et_flex_column et_pb_css_mix_blend_mode_passthrough et_flex_column_24_24 et_flex_column_24_24_tablet et_flex_column_24_24_phone\">\n<div class=\"et_pb_text_24 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h2><strong><span style=\"color: #00ffff;\">\/\/ <\/span><\/strong><b>What Comes Next<\/b><\/h2>\n<\/div><\/div>\n\n<div class=\"et_pb_text_25 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><p>The immediate priority is letting the feedback loop accumulate data. I am trading small size on A-plus and A setups while the system builds its track record. After one hundred resolved outcomes I will publish a follow-up with the actual accuracy data, broken down by grade, regime, and macro theme.<\/p>\n<p>The third tab on the Trading Hub dashboard is in progress, pulling on-chain data from Dune Analytics and direct protocol APIs. The longer-term goal is to correlate macro signals with cross-chain money flows, since capital moves across blockchains in patterns that sometimes precede equity-visible moves in related sectors.<\/p>\n<p>The code is private for now. Whether it goes public depends entirely on what the feedback loop shows after six months of live data.<\/p>\n<p>If you have built something similar or have thoughts on the architecture, I would like to hear about it.<\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_12 et_pb_row et_block_row\">\n<div class=\"et_pb_column_12 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_divider_0 et_pb_divider et_pb_space et_pb_divider_position_top et_pb_module\"><div class=\"et_pb_divider_internal\"><\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_13 et_pb_row et_block_row preset--group--divi-row--divi-sizing--w5u0x3y1pz\">\n<div class=\"et_pb_column_13 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_team_member_0 et_pb_team_member et_pb_bg_layout_dark et_pb_text_align_left et_pb_module et_flex_module\"><div class=\"et_pb_team_member_image et-waypoint et_pb_animation_off\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/web3fuel.io\/article\/wp-content\/uploads\/2025\/06\/avatar.png\" alt=\"Alex Grant\" width=\"200\" height=\"200\" srcset=\"https:\/\/web3fuel.io\/article\/wp-content\/uploads\/2025\/06\/avatar.png 200w, https:\/\/web3fuel.io\/article\/wp-content\/uploads\/2025\/06\/avatar-150x150.png 150w\" sizes=\"(max-width: 200px) 100vw, 200px\" class=\"wp-image-68\" \/><\/div><div class=\"et_pb_team_member_description\"><h4 class=\"et_pb_module_header\">Alex Grant<\/h4><p class=\"et_pb_member_position\">Blockchain Infrastructure & Security Analyst<\/p><div class=\"et_pb_team_member_description_content\"><p class=\"whitespace-normal break-words\"><span style=\"font-weight: 400;\">Hi, I'm Alex, founder of Web3Fuel. My goal is to simplify complex blockchain concepts and provide fuel for the growth of Web3.<\/span><\/p>\n<p class=\"whitespace-normal break-words\"><span style=\"font-weight: 400;\"><b>Currently seeking:<\/b> Technical Writer, Content Strategist, and Developer Relations roles at blockchain protocols and infrastructure companies.<\/span><\/p>\n<\/div><\/div><\/div>\n<\/div>\n<\/div>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>Step-by-step guide to build a multi-agent pipeline with three sequential Claude API calls, a self-calibrating feedback loop, live brokerage integration, and a unified dashboard.<\/p>\n","protected":false},"author":1,"featured_media":736,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[28,24],"tags":[31,30,29,32],"class_list":["post-723","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-trading","category-tutorial","tag-ai","tag-investing","tag-trading","tag-tutorial"],"_links":{"self":[{"href":"https:\/\/web3fuel.io\/article\/wp-json\/wp\/v2\/posts\/723","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/web3fuel.io\/article\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/web3fuel.io\/article\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/web3fuel.io\/article\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/web3fuel.io\/article\/wp-json\/wp\/v2\/comments?post=723"}],"version-history":[{"count":10,"href":"https:\/\/web3fuel.io\/article\/wp-json\/wp\/v2\/posts\/723\/revisions"}],"predecessor-version":[{"id":737,"href":"https:\/\/web3fuel.io\/article\/wp-json\/wp\/v2\/posts\/723\/revisions\/737"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/web3fuel.io\/article\/wp-json\/wp\/v2\/media\/736"}],"wp:attachment":[{"href":"https:\/\/web3fuel.io\/article\/wp-json\/wp\/v2\/media?parent=723"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/web3fuel.io\/article\/wp-json\/wp\/v2\/categories?post=723"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/web3fuel.io\/article\/wp-json\/wp\/v2\/tags?post=723"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}