Inside SNIPER | How FlowSniper’s Active Mode Decides What to Trade
FlowSniper Actual9 min read·Just now--
A code-grounded look at the active scalper bot that scans 128 Bittensor subnets roughly every five minutes, what it watches, how it scores, when it pulls the trigger, and why it exits.
There’s a category of crypto trading bot that call themselves a “rotation bot.” You give it a list of tokens. It cycles capital between them on a fixed schedule. The schedule itself is the strategy. That is not Sniper.
Sniper is FlowSniper’s active scalp engine. It scans every Bittensor subnet on the chain (128 at the time of writing, plus whatever’s been registered since) about every five minutes, scores each one across thirteen active signals at the default configuration, classifies it, and decides whether the setup is worth taking. The schedule is just the metronome. The decisions are the strategy.
The signal vector | sixteen slots, thirteen active
Sniper’s profile holds sixteen weighted signal slots. Three of them ship with weight 0.00 at default. They aren't broken. They're disabled by default. This gives operators more flexibility with their setup.
The disabled three are validator-weight-vector, tempo-recency, and cluster-similarity. They sound clever (and they are, on subnets that share validator sets), but on dTAO each subnet has its own validator population and its own emission schedule. Cross-subnet comparisons of weights and tempos turn out to be apples-to-oranges. The slots remain in the data class. You can re-enable them, and a small number of operators do, weighted lightly.
The thirteen active signals fall into three buckets.
Flow and volume (≈63% of total weight at default).
tao_flow is subnet volume relative to its EMA staking flow. volume_proxy is alpha pool activity, normalised. reserve_change is net TAO inflow over the lookback window. emission is TAO emissions to this subnet. buy_pressure is subnet volume rate vs. historical average. large_buy is single-cycle reserve spike detection. chain_buy is the gap between moving price and spot, a buyback proxy.
If you’ve ever read a Bittensor analyst describe “money is flowing into SN42,” this is the bucket that captures that observation, mechanically.
Price action (≈21% of total weight at default).
price_momentum is alpha token price trend. price_accel is the second derivative; trend strengthening or weakening.
Technical indicators (≈22% of total weight at default).
rsi is relative strength, used as an overbought/oversold filter. macd is moving-average convergence/divergence for trend confirmation. bb_squeeze is Bollinger Band squeeze and breakout. vwap_momentum is volume-weighted price trend.
The buckets matter. Sniper is not a TA bot. Technicals contribute about a fifth of the conviction score. The dominant signal class is what’s actually moving on-chain: TAO inflows, pool activity, large buys. That’s a deliberate design call. dTAO is a market where on-chain data is reliable and abundant, while traditional TA gets noisy on illiquid alpha pools. Treating TA as a confirming filter rather than a primary signal is more honest about where the information lives.
You can see your current weights any time at [1] SNIPER → [8] Parameters → [5] Signal Weights. The auto-tune system (Recon & Calibration) re-fits these weights against your own trade history. The defaults are simply a starting point, not a fixed strategy.
The conviction score is a composite, not a sum
A common misunderstanding: people read “13 active signals” and assume the bot computes a weighted sum and calls it a day. The actual conviction score is a four-part composite.
conviction = w_setup × setup_score
+ w_trigger × trigger_score
+ w_raw × raw_score
+ w_decay × (1 - decay_score)Each of those four components is itself a weighted blend of underlying signals. The point of the composite is to capture different kinds of evidence.
Setup score asks: is the structure here? Are the slow-moving conditions (validator weight stability, tempo, cluster, flow persistence) lined up?
Trigger score asks: did something just happen? Is there a fresh catalyst (a flow event, a price acceleration, a pressure spike)?
Raw score asks: what’s the basic weighted-sum read of all the active signals right now?
Decay score asks: is this opportunity already past? It contributes inversely. High decay subtracts conviction.
A subnet with great setup but no trigger gets parked in TRACKING, not ENGAGE. A subnet with a fresh trigger but no setup behind it is treated as noise. A subnet scoring high on both that’s also showing decay markers gets demoted. This is why Sniper rarely chases late breakouts. The decay component is doing its job.
Lifecycle states and watch stages
Every subnet visible on screen carries two pieces of state: a lifecycle label and a numeric watch stage from 0 to 4. They tell different stories.
Watch stages | how close to ready
The stage progression is where Sniper’s “I stalk before I shoot” character lives.
Stage 0: nothing’s happening, or decay is fatal. Stage 1: setup score crossed its minimum. Stage 2: setup has held above the minimum for at least three consecutive cycles. Stage 3: trigger score crossed its minimum, and decay is still healthy. Stage 4: conviction crossed the entry threshold, decay is healthy, the subnet is entry-ready.
Stages can fall as well as rise. If decay crosses the soft-exit threshold mid-progression, the stage drops by one. If it crosses the hard-exit threshold, the stage instantly resets to zero. If both setup and trigger fall below 0.30, the stage drops by one.
In real time, this means a setup typically takes fifteen to thirty minutes minimum to climb from Stage 1 to Stage 4: three cycles for setup persistence, plus a trigger event, plus enough conviction to cross the entry floor. That’s the honest answer to “why isn’t the bot trading yet?” Sniper waits for evidence to compound.
Lifecycle | what the human sees
The lifecycle label is what shows up in the Threat Board UI.
SWEEPING is gathering data, nothing notable yet. COLD-START means the subnet hasn't been seen for enough cycles to qualify. ACQUIRING means setup has formed. LOCKED ON means setup plus trigger plus healthy decay; stage is at the entry threshold. FADING means decay crossed soft-exit; conviction is bleeding off. EXIT CANDIDATE means decay crossed hard-exit; if you hold this position, the bot wants out.
Watch a Threat Board for a few hours and you’ll see subnets climb the lifecycle. SN42 might enter as SWEEPING, sit there for forty minutes, drift into ACQUIRING, hold there for twenty minutes, and either advance to LOCKED ON (and probably trigger an entry) or fall back to SWEEPING because the catalyst never arrived.
The four classifications
The classify function is short and worth quoting in full.
python
if decay >= hard_exit_decay: return "EVADE"
if conviction >= buy_threshold and entry_ready: return "ENGAGE"
if conviction >= watch_threshold or setup >= min: return "TRACKING"
if conviction <= sell_threshold or exit_signal: return "EVADE"
return "RECON"Default thresholds at v1.1: buy_threshold=0.50, watch_threshold=0.30, sell_threshold=0.20, hard_exit_decay=0.68.
Two details worth flagging.
ENGAGE requires both conviction and entry_ready. A subnet can score high enough on conviction to nominally qualify but still lack the watch-stage progression that entry_ready represents. The bot won't fire on conviction alone. It needs the stage history.
EVADE is checked twice, at the top and the bottom. High decay forces evasion regardless of conviction (a fading subnet can still score well on raw signals). Low conviction or an explicit exit signal also forces evasion. The two checks catch different failure modes.
RECON is the default state. Most subnets, most of the time, are in RECON. That’s correct. At any given moment, only a handful of dTAO subnets are in genuinely tradeable setups. If you’re seeing 50 subnets in ENGAGE, your thresholds are too loose.
Entry | three gates, not one
Even when a subnet hits ENGAGE, the bot doesn’t always trade it. There are three gates.
1. Live mode. Sniper has to be flipped from DRY to LIVE in [5] FIRE CONTROL. Until then, every ENGAGE is logged as a simulated entry but no TAO moves.
2. Sweep prerequisite (10 cycles). Before Fire Control will accept a live flip for Sniper, the bot must have completed at least ten dry-run sweep cycles. At a 5-minute poll, that’s fifty minutes of confirmed signal pipeline before any real money goes anywhere. This is a global gate, not per-subnet.
3. Per-subnet cold-start (3 cycles). A specific subnet has to have been observed for at least three cycles before it can ENGAGE. Even if Sniper is fully warmed up, a freshly-registered subnet won’t be entered for the first ~15 minutes of its existence. This prevents acting on a single anomalous data point.
Add to those: budget caps (per-mode TAO allocation in [13] ARSENAL → [7]), max-trades-per-hour, max-new-entries-per-cycle, daily-deployed-cap, and pool-impact filters. A subnet can pass conviction and stage and still be skipped because its 500-TAO impact would push price too far.
The cumulative effect: Sniper enters a small fraction of the subnets it sees go to ENGAGE. That’s the whole point.
Exits | six priority levels, and the order matters
When multiple exit triggers fire on the same position in the same cycle, the bot has to pick one. Sniper sorts decisions in this priority order.
STOP_LOSS: capital protection. Hard floor; nothing overrides it.TRAILING_STOP: locks in unrealised gains.SIGNAL_EXIT: decay score crossedhard_exit_decay. The signal model is telling you to leave.TAKE_PROFIT: full close at the configured profit target (default 100%).TIME_EXIT: held longer than the maximum hold time. Lowest priority because the position isn't bleeding; it's just stale.PARTIAL_LADDER: staged partial exits at predefined gain levels.
The trailing stop deserves a closer look because Sniper’s implementation is more interesting than the standard “trail by X%” most bots use.
The trail arms when the position’s high-water-mark crosses trailing_stop_arm_profit_pct (default 8%). Until then, no trail. This prevents the trailing stop from triggering on entry noise: the price wiggle that happens in the first few cycles of any new position.
Once armed, the trail tightens as the peak gain grows. The default tiers:
HWM gain ≥ 15%: trail tightens to tiered_trail_15_pct (or 7% min). HWM gain ≥ 25%: trail tightens to tiered_trail_25_pct (or 5% min). HWM gain ≥ 40%: trail tightens to tiered_trail_40_pct (or 3% min).
So a position that ran from entry to +50% and then started giving back will be trailed at a 3 to 5% retrace, not the original 8%. The bot has converted unrealised profit into a tighter floor automatically.
The partial-exit ladder works alongside the trail, not instead of it. Default ladder: [[15.0, 0.20], [40.0, 0.30]]. At +15% gain, sell 20% of the position. At +40% gain, sell another 30%. The remaining 50% rides the trailing stop and take-profit. The ladder is fully configurable in [1] SNIPER → [8] Parameters → [9] Partial Exit Ladder.
Adapting to regime
The piece most “trading bots” miss: stops and entry filters shouldn’t be the same in every market.
Sniper computes a regime label every cycle using signal breadth: the proportion of subnets in ENGAGE vs. EVADE, and the average price momentum. Three regime states: TRENDING_UP, RANGING, CRISIS. The thresholds for each are deliberately not in this article (it’s the kind of detail an adversary would use to spoof regime detection), but the behavioural consequence is public.
CRISIS regime → stops tighten by 25%. The bot becomes more risk-off automatically. entry_score_min also raises.
TRENDING_UP regime → stops widen by 25%. Winners get more room. Entry threshold loosens slightly.
RANGING regime → defaults apply.
The regime label is visible at [6] SITREP. If you've ever wondered why your bot's stops moved without you touching anything, regime change is the answer.
The honest tradeoffs
A few things Sniper doesn’t do, that other bots claim. The omissions are deliberate.
No social sentiment scoring. Twitter sentiment is gameable, lagged, and noisy on Bittensor specifically. The signal-to-noise ratio on #bittensor doesn’t justify the integration complexity. We’d rather lean on what’s settled on-chain.
No backtested-only deployment. Sniper has a backtester ([1] SNIPER → [9] Recon & Calibration) and an auto-tuner that re-fits weights using your real trade history. Both are tools for tuning, not promises of forward returns. The README is explicit: past performance doesn't predict the future, and the bot is built to survive losing periods, not to maximise headline numbers in good ones.
No “set and forget” framing. Sniper rewards operators who watch the Threat Board, understand why a subnet hit LOCKED ON, and intervene when their judgment differs. The pre-trade preview added in v1.1 (visible when you change a parameter, it shows you how many of last week's entries the new threshold would have blocked) is for operators who tune. The 20-slot config undo is for operators who change their mind. These are tools for engaged users, not features that imply you can install and ignore.
If you want a bot that promises numbers and runs on autopilot, Sniper is the wrong tool. If you want an active scalper that documents its reasoning, exposes its parameters, and stays under your own keys on your own VPS, that’s what’s in the box.
FlowSniper is a self-hosted Bittensor dTAO trading bot. It runs on your own VPS, signs trades with your own wallet, and never transmits keys or trade history to us. Four trading modes (Sniper, Sentinel, Designate, Shadow) share one wallet and one operator.
Field Manual: flowsniper.ai/docs. Mode reference: flowsniper.ai/mode-reference.