<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
      <title>Bombatag - Blog</title>
      <link>https://bombatag.com/blog/</link>
      <description>Bombatag research project</description>
      <generator>Zola</generator>
      <language>en</language>
      <atom:link href="https://bombatag.com/blog/rss.xml" rel="self" type="application/rss+xml"/>
      <lastBuildDate>Sat, 29 Aug 2026 00:00:00 +0000</lastBuildDate>
      <item>
          <title>Building a two-shift AI newsroom</title>
          <pubDate>Sat, 29 Aug 2026 00:00:00 +0000</pubDate>
          <author>maksim07</author>
          <link>https://bombatag.com/blog/two-shift-ai-newsroom/</link>
          <guid>https://bombatag.com/blog/two-shift-ai-newsroom/</guid>
          <description xml:base="https://bombatag.com/blog/two-shift-ai-newsroom/">&lt;p&gt;Financial markets do not have a natural ending. Europe closes while America is still trading;
crypto never closes at all; and by the time one narrative has settled, another data release is
already changing it. I wanted the News section of this site to keep pace without turning it into
an endless stream of copied headlines.&lt;/p&gt;
&lt;p&gt;The result is a small, automated newsroom with two shifts. At 07:00 it publishes a briefing for
the day ahead. At 20:00 it returns to explain what actually happened. Claude researches and
writes, Codex creates the editorial artwork, and a deliberately unglamorous shell script decides
whether anything is safe to publish.&lt;/p&gt;
&lt;h2 id=&quot;two-runs-two-editorial-jobs&quot;&gt;Two runs, two editorial jobs&lt;/h2&gt;
&lt;p&gt;The whole system begins with two entries in my crontab:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0 7 * * *  /bin/bash ~/bin/financial-news-digest.sh  # morning&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0 20 * * * /bin/bash ~/bin/financial-news-digest.sh  # evening&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both invoke the same wrapper and both ask for the previous 24 hours, but they do not produce the
same article twice. The wrapper reads the real clock before Claude starts. A morning run is told
to include the day&#39;s scheduled data, central-bank events, the next relevant FOMC date and any
index-rebalancing deadline. The evening run is a same-day recap and deliberately drops that
forward calendar.&lt;/p&gt;
&lt;p&gt;That distinction matters. The first briefing answers, “What changed overnight, and what could
move the market next?” The second asks, “Which of those risks mattered by the close?” It gives
the feed a rhythm rather than simply doubling its volume.&lt;/p&gt;
&lt;h2 id=&quot;claude-runs-the-news-desk&quot;&gt;Claude runs the news desk&lt;/h2&gt;
&lt;p&gt;Claude starts as a specialist financial-news agent with a narrow assignment: research the last
24 hours across macroeconomics, US and European equities, commodities, crypto prices and crypto
regulation. It looks for primary or reliable sources, keeps the concrete market levels and
percentage moves, and avoids manufacturing a story when the window is quiet.&lt;/p&gt;
&lt;p&gt;The first output is a compact Telegram briefing. That is the fast channel: roughly a phone
screen of text, designed to be useful now. Once that send has been attempted, the same research
is passed through a second Claude skill that acts more like an editor. It restores headings and
source links, keeps the important figures, writes a real headline around the dominant story and
turns the briefing into a 300–500 word entry for this site&#39;s News section.&lt;/p&gt;
&lt;p&gt;This is an important part of the setup: the web post is not a paste of the Telegram message.
One is an alert; the other is a dated market snapshot that should still make sense when opened
from an RSS reader several days later.&lt;/p&gt;
&lt;h2 id=&quot;codex-draws-the-front-page&quot;&gt;Codex draws the front page&lt;/h2&gt;
&lt;p&gt;Each digest also gets a companion image. Claude sends the finished digest through a small MCP
tool, which invokes a script backed by the Codex CLI. Codex is asked to choose one genuinely
market-moving story and reduce it to a single visual metaphor rather than attempting to draw a
dense dashboard of every asset mentioned.&lt;/p&gt;
&lt;p&gt;The art direction is intentionally consistent: warm newsprint, charcoal linework, muted red,
plenty of negative space and no logos or portraits of public figures. There can be one short
headline and, at most, one exact data point from the digest. The result is closer to an editorial
newspaper illustration than a synthetic trading terminal.&lt;/p&gt;
&lt;p&gt;That division of labour works well. Claude has the full research context and controls the words;
Codex gets a much smaller creative problem—find the visual centre of gravity. The PNG is sent
with the Telegram update. On the site, the same image can also serve as the article&#39;s hero, list
thumbnail and social preview; if the asset is unavailable, the post is published without it.&lt;/p&gt;
&lt;h2 id=&quot;the-boring-code-has-the-final-vote&quot;&gt;The boring code has the final vote&lt;/h2&gt;
&lt;p&gt;The language model does not decide the filename, timestamp, Git branch or whether today is a
publishing day. Those belong to the wrapper script because they should be deterministic.&lt;/p&gt;
&lt;p&gt;Cron still sends a Telegram digest every day, including weekends. The site feed is more
selective: automated posts are skipped on weekends, UK bank holidays and NYSE market holidays.&lt;/p&gt;
&lt;p&gt;When publishing is allowed, Claude may write exactly one Markdown file. It cannot run Git or
deploy the site. After Claude exits, the wrapper takes over:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It looks for the matching generated image and, when present, copies it into the site&#39;s tracked
static assets.&lt;/li&gt;
&lt;li&gt;It builds the entire Zola site in a temporary directory.&lt;/li&gt;
&lt;li&gt;It stages only the new post and its matching image, even if I have unrelated work in progress.&lt;/li&gt;
&lt;li&gt;It commits and pushes to &lt;code&gt;master&lt;/code&gt;, which triggers the GitHub Pages deployment.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If the image failed, the article can continue without it. If the Zola build fails, nothing is
committed. If the push is rejected, the commit stays local for inspection—the automation never
rebases or stashes my work to force its way through.&lt;/p&gt;
&lt;h2 id=&quot;from-markdown-to-a-separate-feed&quot;&gt;From Markdown to a separate feed&lt;/h2&gt;
&lt;p&gt;The final piece is Zola itself. News lives in its own content section with feed generation
enabled, so every published digest becomes an HTML page and an item in &lt;code&gt;/news/rss.xml&lt;/code&gt;. The blog
keeps its separate &lt;code&gt;/blog/rss.xml&lt;/code&gt;; readers interested in market briefings do not have to mix
them with longer research posts, and vice versa.&lt;/p&gt;
&lt;p&gt;There is no database and no publishing API. The durable artefact is a Markdown file, reviewed by
the same static-site build used for everything else here. That simplicity makes the automation
easy to inspect: the post, its sources, its image and the commit that published it all remain
together.&lt;/p&gt;
&lt;h2 id=&quot;the-useful-boundary&quot;&gt;The useful boundary&lt;/h2&gt;
&lt;p&gt;The interesting part of this setup is not that an AI can write a market summary. It is deciding
where its judgement is valuable and where it is dangerous. Selecting the dominant story,
compressing research and finding a visual metaphor benefit from Claude and Codex. Calendars,
paths, permissions, validation and version control benefit from ordinary code with predictable
failure modes.&lt;/p&gt;
&lt;p&gt;Twice a day the creative half wakes up, does its shift and hands the result back. The mechanical
half checks the doors before anything goes live. That boundary is what turns a clever demo into
a news feed I can leave running.&lt;/p&gt;
</description>
      </item>
      <item>
          <title>How much profit should a trailing stop give back?</title>
          <pubDate>Fri, 28 Aug 2026 00:00:00 +0000</pubDate>
          <author>maksim07</author>
          <link>https://bombatag.com/blog/dynamic-trailing-stop/</link>
          <guid>https://bombatag.com/blog/dynamic-trailing-stop/</guid>
          <description xml:base="https://bombatag.com/blog/dynamic-trailing-stop/">&lt;p&gt;In the trading system I am building, crossing the take-profit barrier does not have to end a
trade. It can be the point where the strategy stops waiting for a target and starts protecting a
winner: follow the best price, give the move some room, and close only when it turns back.&lt;/p&gt;
&lt;p&gt;The awkward part is deciding how much room is enough. Close too tightly and ordinary market noise
cuts short every good move. Wait too long and a profit that was already available leaks away.&lt;/p&gt;
&lt;p&gt;My first instinct was that this should be a dynamic decision. I already had a calibrated one-minute
direction signal, so why not let a confident model loosen the trailing stop and tighten it when
confidence fades? It is a plausible idea—and exactly the kind of plausible idea that needs a
backtest before it finds its way into a trading system.&lt;/p&gt;
&lt;h2 id=&quot;isolating-the-exit-decision&quot;&gt;Isolating the exit decision&lt;/h2&gt;
&lt;p&gt;I built a separate research pipeline for this exit experiment using BTCUSDT aggregated trades from
January 2024 to January 2026. It reconstructs the top of the book, buys at the ask and values the
exit at the bid, so the test has to cross the spread rather than pretending every trade happens at
the last price.&lt;/p&gt;
&lt;p&gt;The entry side is deliberately fixed. I take opportunities where the calibrated direction score
is in roughly its top 5%, then keep only the positions that reach a 30 bps profit barrier before a
20 bps stop or a two-hour timeout. That leaves &lt;strong&gt;602,400 winning positions&lt;/strong&gt;. Closing immediately
at the barrier is the baseline, worth &lt;strong&gt;15.64 bps per trade net of fees&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;From that same decision point I replayed several trailing exits. Each one follows the bid to a new
peak, then closes after giving back a fraction &lt;code&gt;g&lt;/code&gt; of the best profit seen so far. With &lt;code&gt;g = 0.10&lt;/code&gt;,
for example, a trade that reaches 50 bps of peak profit is allowed to retreat by 5 bps before it is
closed.&lt;/p&gt;
&lt;p&gt;I tested fixed values from 1% to 30%. I also tested the idea I was more interested in: a dynamic
rule that recalculates the give-back from the latest model score. Weak confidence pulls the leash
tight; strong confidence allows as much as a 30% give-back.&lt;/p&gt;
&lt;p&gt;This is a paired exit experiment, not a portfolio backtest. The candidate positions overlap, so I
would not add their PnL together and call it a realizable return. What I can compare cleanly is how
each exit behaves on exactly the same set of winning trades.&lt;/p&gt;
&lt;h2 id=&quot;the-boring-rule-wins&quot;&gt;The boring rule wins&lt;/h2&gt;
&lt;p&gt;The best fixed result came from &lt;strong&gt;&lt;code&gt;g = 0.10&lt;/code&gt;&lt;/strong&gt;, which added &lt;strong&gt;1.96 bps per trade&lt;/strong&gt; over closing at
the barrier—a &lt;strong&gt;12.6% uplift&lt;/strong&gt; on the baseline. It was positive in all 25 months in the sample and
kept a position open for only another 54 seconds on average.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/blog/dynamic_trailing_stop/uplift_by_giveback.png&quot; alt=&quot;Mean uplift by give-back percentage&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I would not read too much into 10% being the highest dot on the chart. The useful result is the
shape of the curve: it is remarkably flat. A 1% give-back added 1.95 bps; 5% added 1.95 bps; 15%
still added 1.91 bps. Even the much looser 20% and 30% rules remained profitable against the
baseline, although they held positions longer for less average uplift.&lt;/p&gt;
&lt;p&gt;In other words, trailing the winner mattered much more than finding a perfect trailing parameter.
Ten percent is a sensible default, not a magic number.&lt;/p&gt;
&lt;h2 id=&quot;winning-less-often-can-still-make-more&quot;&gt;Winning less often can still make more&lt;/h2&gt;
&lt;p&gt;The average hides the most interesting part of the result. The 10% rule improved only &lt;strong&gt;49.5% of
trades&lt;/strong&gt;. Its median uplift was actually slightly negative. It still won overall because the moves
that continued running created a long right tail large enough to pay for all the small give-backs.&lt;/p&gt;
&lt;p&gt;Tighter rules feel better trade by trade. The 1% rule beat the baseline almost 70% of the time and
closed after another 12 seconds on average. Looser rules are the opposite: the 30% rule improved
only 36% of trades, but occasionally stayed with a much larger move.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/blog/dynamic_trailing_stop/scenario_comparison.png&quot; alt=&quot;Comparison of fixed give-back scenarios against the dynamic rule&quot; /&gt;&lt;/p&gt;
&lt;p&gt;That is the real trade-off. A tight trail collects many small improvements. A loose trail accepts
frequent small disappointments in exchange for rare, outsized winners. Looking only at win rate
would choose the wrong exit.&lt;/p&gt;
&lt;h2 id=&quot;the-signal-did-not-know-when-to-hold&quot;&gt;The signal did not know when to hold&lt;/h2&gt;
&lt;p&gt;The dynamic rule added &lt;strong&gt;1.90 bps per trade&lt;/strong&gt;, just short of the fixed 10% rule&#39;s 1.96 bps, while
holding positions longer on average. That is not a disastrous result—the rule still improved the
baseline—but the extra complexity did not earn anything.&lt;/p&gt;
&lt;p&gt;I also grouped the trades by model confidence at the moment the take-profit barrier was reached.
If the original intuition was right, stronger signals should have produced a clear increase in the
value of giving a trade more room. They did not. The curves move around, but there is no useful
monotonic relationship for the dynamic rule to exploit.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/blog/dynamic_trailing_stop/uplift_by_signal.png&quot; alt=&quot;Uplift by signal strength at the trigger point&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This does not mean the direction model is useless. It already did its job by selecting the entry.
It means that the same one-minute score does not contain enough new information, once the profit
barrier has been reached, to manage the final few seconds of the exit better than a fixed rule.
Entry confidence and exit timing are related questions, but they are not the same question.&lt;/p&gt;
&lt;h2 id=&quot;what-i-would-put-into-the-system&quot;&gt;What I would put into the system&lt;/h2&gt;
&lt;p&gt;The practical conclusion is pleasantly simple: start with a fixed 10% risk budget and do not
overfit the second decimal place. The broad plateau around the optimum matters more than the exact
winner, and the consistency across months makes the result more convincing than a single aggregate
number.&lt;/p&gt;
&lt;p&gt;The live take-profit strategy has a little more machinery than this isolated test. A barrier breach
must hold briefly before trailing begins, and the live band is measured relative to the take-profit
barrier rather than reproducing this backtest formula exactly. It also has to deal with real fills,
commissions, exchange step sizes and closing orders. So I treat this result as evidence for the
design and its default—not as a claim that the production path has been simulated line for line.&lt;/p&gt;
&lt;p&gt;I still like the dynamic idea, but it now has a higher bar. To justify shipping it, I would want a
signal built specifically for continuation after the barrier, not a repurposed entry signal with a
more complicated mapping. Until then, the fixed rule is easier to explain, easier to operate and,
on this sample, marginally better.&lt;/p&gt;
</description>
      </item>
    </channel>
</rss>
