🍺
/Documentation

Reference

Best Practices

Last updated March 1, 2026

Distilled guidance for building robust, reliable strategies on Hornpub. Follow these principles to avoid the most common pitfalls.

Strategy Best Practices

1. Always guard entries with NOT In Position

Without this guard, your strategy buys on every tick the entry condition is true, potentially buying hundreds of times before the price moves. Unless you intentionally want to average down, always wrap BUY blocks with NOT In Position.

2. Always have an exit

Every strategy that can open a position must also be able to close it. Include at minimum a Take Profit and a Stop Loss, or a time-based exit (Bars Since Entry). An open position with no exit condition can stay open indefinitely.

3. Backtest before going live

Even a simple backtest over 3 months of hourly data will reveal obvious flaws: too many trades, poor win rates, excessive drawdown. Run the backtest, export the CSV, and review the trade log before activating a strategy.

4. Start with longer intervals

A 5-minute interval executes 288 times per day per symbol. At that frequency, spread, fees (in live trading), and market noise dominate. Start with 1-hour or 4-hour intervals and only go shorter if the strategy logic requires it.

5. Use filters to prevent counter-trend trades

RSI-based mean-reversion strategies can suffer badly in strong trends. Add a Trend Direction filter (Bullish) as an AND condition to only buy into dips within an uptrend, not during a crash.

6. Use Cooldown Bars after losses

After your stop-loss fires, the market is likely still moving against you. A 20–50 bar cooldown prevents re-entering immediately into a continuing adverse move.

7. Keep strategies simple

Complex strategies with many conditions are harder to debug, slower to execute (risking timeouts), and more prone to overfitting in backtests. A 2–3 condition entry with a TP/SL exit is more robust than a 10-condition system tuned to historical data.

8. Monitor logs for the first 24 hours

After activating a new strategy, check the Logs tab frequently for the first day. Look for unexpected skips, errors, or wrong symbols. Enable Advanced Logging temporarily to see exactly what the Runner sees on each tick.

FAQ

Why isn't my strategy trading even though it's live?
Check the Logs tab. Common causes: (1) You changed the editor but didn't re-compile. (2) Trade hours setting is blocking execution. (3) The entry condition (e.g. RSI < 30) hasn't been met. (4) You're already in a position and the NOT In Position guard is blocking entry.
Can I run multiple strategies for the same symbol?
Yes, create separate projects. Each project maintains its own independent positions and trade history. Two projects can both trade BTCUSDT simultaneously with their own positions tracked independently.
What happens to open positions when I pause a project?
Open positions stay open. The Runner simply stops evaluating your strategy, so no exits will fire automatically. You need to re-activate the project for exit logic to run.
Why does PREV return NaN initially?
PREV needs N ticks of history before it can return a value. On the first tick, there's no prior value, so it returns NaN. Wrap conditions using PREV with an additional check to ensure the value is finite before acting on it. The buffer fills up after N ticks.
My Cross Up block never fires. Why?
Cross Up requires comparing the current tick's values to the previous tick's. On the first tick after a project restart, no prior values exist, so it returns false. It also requires the condition to be false first, then true, if the fast EMA has been above the slow EMA for many bars, Cross Up won't fire until it dips below and then crosses back up.
What timeframe do the indicators use?
All indicator blocks in the current version use the 1m (1-minute) timeframe kline data from the cache by default. For the backtest, the timeframe you select in the setup is used. Live execution always reads 1m cached data.
How is realized PnL calculated?
PnL per sell = (exit_price − entry_price) × quantity_sold. For partial sells, the entry price used is the volume-weighted average entry of the whole position. Fees are currently simulated as zero.