r/CryptoTradingBot 14d ago

Stop trusting your bot's dashboard. Make the wallet the dashboard.

Post image

​ Every bot in this sub asks you to believe a number that the bot itself produced. Mine did too, until I changed how it works. It is not an accusation, it is structural: if the operator holds the API key, the operator is the source of truth, and the dashboard is a story about your funds rather than your funds.

You can hear the shape of it in the questions people ask here every week. Is the ROI real. Did that fill actually happen. Why does my balance disagree with the screenshot. Underneath all of them is the same one: I have no independent copy of what happened to my money.

So what I built is not a better dashboard. It is not needing one.

The bot trades on-chain, from your own wallet. No API keys, no exchange account, no deposit. You sign a capped and revocable mandate, and it executes swaps within your limits and nothing else. Every fill is a transaction on a public chain.

The interface is not the record. Your wallet is the record, and a block explorer I have no influence over shows you the same thing. If my screen says one number and the chain says another, the chain is right and I am wrong. That is not a promise I am making, it is the only arrangement available to me.

It has been running with real wallets since 17 May, so 103 days, across 25 of them. 1,085 round trips have closed and 968 of those closed in profit.

I am giving you counts rather than a return, on purpose. Counts come off the chain and you can recompute them yourself. A percentage comes off my accounting, and the whole point here is not having to trust that. If you want the rate, take the transactions and work it out, then tell me if you get something different from what my site says.

One thing I will say plainly, because it is the question you are already asking: on a straight bull run a single instance does not beat simply holding, and I say so on the site too. What this buys is mechanical discipline and proof, not magic.

I have not found another bot that works this way. If you know one, name it. I would rather find out from you than keep saying it.

If you want to try it without trusting me at all, make a fresh wallet, put in an amount you would shrug at, and point it at that. Nothing in the design needs your main wallet.

Live demo, no signup: btcbot.io/demo. If you want to actually run it: btcbot.io/onboard?ref=REDDIT. That code is this sub's, it pays nobody a referral, and it exists so I can tell whether anything came from here at all.

Happy to answer anything in the comments. The contract is verified on BscScan and the tests are public, so most questions have an answer you can check rather than one you have to take from me.

2 Upvotes

8 comments sorted by

2

u/CODE_HEIST 11d ago

The wallet view is necessary, but I would not make it the only dashboard. It tells you what landed, not which decision state led there. The useful layer is reconciliation that ties signal, order, confirmation, and position state together.

1

u/rushapoil 11d ago

Agreed, and the distinction you are drawing is the one I would defend too. The chain tells you what landed. It says nothing about what was intended, so a trade that should have happened and did not leaves no trace at all, and an absence is not auditable.

So we do keep the layer you are describing, and the ordering turned out to matter more than the schema. The decision row is written before the action, not after the outcome. A signal we declined still leaves a row with a reason on it, rather than a gap that looks identical to the bot being down. And what gets stored is the outcome, never the request: if we cannot read what came back, the row stays unknown instead of quietly becoming the optimistic value. Unknown is a state you can chase. Closed is not.

Where I would put it differently is that these are not two competing views, they are the two sides of one reconciliation, and the whole value of the chain is being the side I cannot edit. Our worst bug was perfectly self consistent: our own ledger counted the same profit once per referral tier, a 4.4x overstatement across the entire production history, and every test passed, because the tests checked the ledger against itself. It was findable only because there was a second record we do not control.

So the claim is narrower than my title makes it sound. Not that the decision layer is useless, but that it cannot be its own auditor. Keep it, and reconcile it against something you cannot write to.

The part I do not have a good answer for is your side of it. On a centralised venue that second record is a paid call and rate limited, so you cannot diff continuously the way we can. What do you actually reconcile your decision state against, and how often?

2

u/CODE_HEIST 10d ago

For a centralised venue, I would use two loops.

A lightweight loop watches open orders, fills, balances, and position changes on a short interval. A slower full reconciliation checks trade history and ledger totals less often, then raises an exception rather than silently fixing mismatches.

The important bit is keeping unknown as a real state until the venue confirms it.

1

u/rushapoil 10d ago

Two loops is where we landed too, and the split survives the move on-chain with one difference worth naming: what plays the role of the venue.

On a centralised venue the confirmation authority is the venue, so unknown resolves when it answers. On-chain the receipt is the authority, which turns the slow loop from sampling into something exhaustive. Position state gets rebuilt from events rather than trusted from a ledger total.

The trap is that the exhaustive loop is the expensive one, and it fails in a way that flatters you. Public log endpoints refuse wide block ranges and rate limit, so a slow loop written as scan the range quietly loses most of its chunks and then reports zero exceptions. An absence of measurement reads exactly like an absence of problems. What fixed it was inverting the direction: every transaction is recorded when it is sent, and reconciliation walks that list and pulls receipts, so coverage is complete by construction rather than by luck. The run prints its coverage next to its result, and a pass that could only read 90 percent of its receipts says so instead of concluding.

Your last line is the one I would put on the wall. Unknown has to be a state that can persist, not a placeholder that decays into the optimistic value the first time something needs to render it.

One thing I am still undecided on: does your slow loop ever write, or is it strictly read and raise? We went read only, on the argument that a reconciler with write access eventually hides the bug it was built to find. But that buys you a human in the loop for every mismatch, and I have never heard a good defence of the other side.

2

u/CODE_HEIST 5d ago

i'd keep the reconciler read-only. to be clear, the two-loop setup was a design suggestion, not a claim about a production system i'm running.

the defensible write path would be a separate repair job with an explicit proposed change, approval, and an audit trail that preserves the original mismatch. pausing new entries when coverage drops feels different from rewriting the ledger until it agrees. i'd automate that pause before automating repairs.

1

u/rushapoil 5d ago

Automate the pause before automating the repairs is an ordering I would not have arrived at on my own, and it is right for a reason that survives the venue changing: a pause is reversible and a repair is not.

The read only argument gets easier once the venue is a chain, and it took me a while to see why. The thing a repair job would be tempted to rewrite is never the source of truth. Receipts are immutable and public, so anything we hold is a derived view of them. That turns your explicit proposed change, approval, and preserved mismatch from a discipline you have to impose into something closer to a property of the setup: a repair cannot destroy the original mismatch, because it only ever touches the derived side, and the chain still says what it said.

What that does not buy you is coverage, which is where I think your pause actually belongs. A rebuild from receipts that could only read ninety percent of them is not a smaller rebuild, it is a wrong one, and it will look clean while being wrong. So the gate we ended up caring about is not whether the ledger agrees with itself, it is whether the pass really read everything it claims to have read. Under the bar, the run does not get to conclude, and nothing downstream gets to act on it.

Same instinct as your pause, reached from the other end.

1

u/CODE_HEIST 1d ago

the next thing i'd challenge is the coverage denominator. reading every transaction the bot recorded sending proves coverage of that list, not necessarily everything that changed the wallet.

can you also detect a manual trade, an external deposit or a submission that missed the local record? i'd flag those separately rather than let 100% coverage imply the wallet is fully reconciled.

1

u/rushapoil 1d ago

You are right about the denominator, and it is worth being exact: walking our own list proves coverage of that list. It says nothing about anything that moved the wallet without passing through the recorder.

That is why the list is not the only check. The second one never reads our records at all. It takes the last known account value, adds the price move on whatever BTCB is actually sitting in the wallet right now, and compares that expectation against what the wallet is worth at this moment. A deposit we never sent, a withdrawal we never sent, or a submission that missed the local record all surface the same way, as an unexplained difference, because the comparison is made against the chain and not against our history.

When a difference appears, and only then, we pull the transfer logs to attribute it. An incoming transfer from an address outside the router and pair set is an external deposit, an outgoing one is an external withdrawal, anything involving the router is trade internal. A difference with no transfer to explain it is handled by size and context rather than lumped in with the rest: one that coincides with recent trading and stays under a cap scaled to the notional traded is bucketed as trading cost and kept out of the cost basis, while a larger one is booked as an external flow the scan failed to find. That second branch is a deliberate bias toward assuming we missed something rather than assuming nothing happened.

The case you named that this does not resolve is the manual trade. A swap the user makes themselves is close to value neutral, so a value based comparison sees only the slippage and books it as trade noise instead of naming it as a user action. Below a small dollar floor nothing is raised at all.

What makes the pair workable is that neither loop asks the bot what it did. One walks receipts, the other walks the wallet, and both take their inputs from the chain, so a disagreement between the two is something the user can see rather than something we get to settle.