Same account. Same market. A different decision process.
The “before” example is reconstructed from the system’s code and a recorded market measurement. The “after” example is an illustration of what the system could do during a later period of higher volatility. It is not a promise that the market will move as described, or that any profit target will be reached.
The original system could set a profit target without knowing how much the complete trade would cost. That allowed it to close a trade at a small gross profit while still losing money after fees. Here is the exact result of the recorded trade:
The improved system asks a more important question first:
Before reviewing the trade, we need to establish the account’s limits. The position had a notional value of $1,982. Notional value is the total market value of the position, not the amount of cash posted as margin.
Code-derived The code limits gross notional exposure to eight times the capital allocated to the strategy (authority.ts:156). Preview item 13 rejects positions above this limit.
maximumGrossNotionalUsd = 8 × allocated capital
A position worth $1,982 therefore requires at least:
$1,982 ÷ 8 = $247.75
Using the exact threshold, the allocated capital must have been approximately $250 or more. The resulting mandate was:
| Limit | Amount |
|---|---|
| Maximum gross exposure | $2,000 |
| Total loss budget | $87.50 |
| Planned risk per position | $17.50 |
The agent wakes into a quiet two-hour window. It sees one timeframe and no cost information of any kind — because no tool in the toolkit reports a fee.
The agent reads observedVolatility for the mission’s main timeframe: one-minute candles
covering 120 bars, or two hours of market activity. The market is quiet:
| Measurement | Result |
|---|---|
| ATR over 14 bars (average recent price movement per candle) | $0.857 |
| Total two-hour price range | $7.30 |
| Median (p50) favourable move over 10 minutes | $1.10 |
| 75th-percentile (p75) favourable move over 10 minutes | $1.60 |
It sees no information from longer timeframes (15-minute or one-hour candles). More importantly, it receives no estimate of fees, spread, or slippage. No available tool reports these costs.
The agent follows the formula described in the tool:
$1.60 expected move ÷ $1,873 market price = 0.0854%
It applies that percentage to a $1,982 position:
0.0854% × $1,982 ≈ $1.70
So it sets targetProfitUsd: 1.70 and a stop $3 below entry.
The planned loss at the stop is approximately $3.18, well below the $17.50 risk
limit — so the stop passes validation. The profit target does not.
targetProfitBasis is optional, and the validation check described in the comment at
wakeup.ts:148
was never implemented. The system accepts a profit target without checking whether it covers the
trade’s costs.
The server uses a crossing immediate-or-cancel order — it attempts to fill immediately at the
best available market price and cancels any unfilled amount. Position value:
1.06 × $1,870 = $1,982. At a taker fee of five basis points (0.05%), the entry fee is
$1,982 × 0.05% = $0.99.
ensureProfitTargetArmed registers a pnl_above watch at $1.70 in
TradingTurnCoordinator.ts:343,
plus a 3-minute staleness reassessment. Every two seconds, the system checks whether unrealized
profit has reached the target — using the exchange’s mark-price calculation. That number is
gross profit. It does not subtract the entry fee or the future exit fee.
Unrealized gross profit reaches $1.75. The watch fires once, then becomes inactive.
The agent wakes with wakeReason: "profit_target"; the tool description says the default
response is to close.
The exit fills near $1,871.50. Gross realized profit ≈ $1.59. Exit fee ≈ $0.99.
The agent reports the trade as a win. The account has actually lost 39 cents.
The profit target was lower than the cost of entering and exiting the position. A successful trade would earn only about $1.70 to $1.75 before fees, while round-trip fees were approximately $1.98. Every target hit would still lose about $0.25 to $0.40 after fees.
A stop-out would lose approximately:
$3.18 trading loss + $1.98 fees = $5.16
The result is structurally unprofitable:
A cost-estimation tool such as trading_estimate_costs could give the agent one crucial field:
breakEvenPriceMoveUsd — the minimum price movement needed to recover the costs of entering
and exiting.
Both profit and fees increase with position size. Gross profit is approximately
price movement × position size; round-trip fees are approximately
position size × asset price × fee rate × 2. Because both sides scale with size, increasing the
position does not make an uneconomic price target profitable. Leverage also does not change the required
movement in the asset’s price.
Code-derived At a price near $1,870 and a fee of five basis points on entry and exit, the fee-only break-even move is approximately:
$1,870 × 0.10% = $1.87 per ETH
After allowing for spread and slippage, the estimated break-even move becomes approximately:
$1.94 per ETH — the same whether the position is 0.1 ETH or 10 ETH.
| Holding period | Measured favourable move |
|---|---|
| 10-minute median (p50) | $1.10 |
| 10-minute 75th percentile (p75) | $1.60 |
| 20-minute median (p50) | $1.90 |
| Estimated break-even move | $1.94 |
The following sequence is illustrative. It shows how the decision process could change if the agent could measure costs, compare multiple timeframes, wait for better conditions, and actively manage a profitable position. It does not claim that the market will produce these movements.
The agent measures both one-minute and 15-minute data, and calls
trading_estimate_costs. The estimate reports:
| Cost measurement | Result |
|---|---|
| Estimated round-trip cost | $2.06 |
| Break-even price move | $1.94 / ETH |
It then builds a target ladder — a set of possible profit levels rather than one fixed exit point. Every initial target fails:
| Scenario | Estimated net |
|---|---|
| Conservative target | −$0.89 |
| Base target | −$0.36 |
The expected reward is too small compared with any stop wide enough to survive the market’s normal movement (~$0.86). The system concludes the trade does not justify its risk.
The agent does not open a position. It publishes a strategy containing:
insufficientVolatility: true · currentAction: "waiting"
And records:
candle_close watch above the range high at $1,878,No position, no fees, no market exposure. Waiting is the correct trading decision. The original system had no process that could reliably reach this conclusion.
The agent measures the market again. New readings:
| Measurement | Result |
|---|---|
| 15-minute ATR (average recent movement) | ≈ $9 |
| One-hour median (p50) favourable move | ≈ $14 |
| One-hour 75th-percentile (p75) favourable move | ≈ $22 |
The strategy now uses a 15-minute thesis timeframe and an expected one-hour hold — not by preference, but because that is where measured movement becomes large enough to exceed trading costs.
Still 1.06 ETH; about $3 of the breakout move has already happened, so remaining expected movement is reduced accordingly:
| Target level | Move/ETH | Gross | Net | Return on $100 | Hit rate |
|---|---|---|---|---|---|
| Conservative | $11 | $11.66 | $9.60 | 9.6% | ~50% |
| Base | $19 | $20.14 | $18.08 | 18% | ~25% |
| Extension (to structure) | $26 | $27.56 | $25.50 | 25% | — |
Stop one 15-minute ATR below the breakout. Estimated risk:
$9.54 price risk + ~$1 exit cost = $10.54, inside the $17.50 limit. All three gates pass,
so it enters — targetProfitUsd set to the conservative level,
targetProfitBasis recording the full calculation.
The system activates: a pnl_above watch at $11.66, a candle_close invalidation below $1,861, and a scheduled reassessment.
Implementation detail: the coverage floor in
watch.ts:153
is min(max(3 × bar duration, 2 min), 15 min). Because the maximum is 15 minutes, even a
15-minute strategy is reassessed four times per hour.
Price ≈ $1,881; gross unrealized profit ≈ $11.66. Instead of automatically closing, the agent checks: is volatility still increasing? Are 15-minute candles still making higher highs? Is sell-side liquidity thin above? Has the thesis been invalidated?
In this illustration, the trend remains intact. The agent extends:
pnl_giveback watch $4.66 below the highest profit,modify_stop.The position is now protected: worst case is around break-even after costs, while about $18 of net upside remains armed.
Gross profit ≈ $20.14. The agent closes half — sells ≈ 0.53 ETH, realizes ≈ $9 net — then recalculates the ladder for the remainder, updates risk, and re-arms.
Highest gross profit was ≈ $22. Profit falls to $17.30; the
pnl_giveback watch fires. The agent closes the rest rather than watching a strong
winner return to its starting point.
The agent compares maximum favourable excursion (the highest unrealized profit reached, ≈$23) against the profit the ladder captured (~78%), confirms it followed its own rules, schedules a 30-minute reassessment, and returns to research. It does not immediately re-enter.
| Outcome | Original process | Improved process |
|---|---|---|
| Net result | −$0.39 | ≈ +$17 |
| Margin used | $100 | $100 |
| Approx. return on margin | −0.39% | +17% |
| Planned risk | ≈ $5.16 at the original stop, incl. fees | ≈ $10.54 |
| Cost considered before entry | No | Yes |
| Ability to wait | No reliable mechanism | Yes |
| Exit structure | One fixed target | Target ladder with partial exits and a trailing giveback rule |
It must also be high enough to cover entry fees, exit fees, the bid–ask spread, expected slippage, and the risk taken to earn it. When the market is not moving enough to cover those costs, increasing position size does not solve the problem. The correct action is to wait.
When conditions improve, the agent can enter with a plan that defines: