-
Notifications
You must be signed in to change notification settings - Fork 440
A python script is given access to user's binance or bybit account and listens to websocket stream of live trades in futures markets, automatically creating and cancelling limit buy and sell orders.
The bot bases its decisions on account's positions, open orders and balance, and multiple EMAs of different spans.
Bot's live behavior is deterministic and may be simulated on historical price data, using the included backtester.
Its behavior is changed by adjusting the configuration to suit a particular market and user's preference.
Configuration's parameters may be optimized to a given period of historical data by backtesting up to thousands of candidates, converging upon the config whose backtest result best satisfy specified criteria.
The bot's purpose is to accumulate tokens over time. It is observed that prices in a market will fluctuate up and down, creating opportunities for capitalizing on the "noise".
passivbot may be described as a market making DCA scalping grid trader.
-
Market maker: passivbot is a pure maker. It never takes orders, only makes them.
-
DCA: Dollar Cost Averaging. It will typically make up to several reentries after an initial entry, in an attempt to acheive better average entry price.
-
Scalping: It will typically close positions at small markups, in the range of 0.1-2.0%
-
Grid trading: Its reentries may be calculated in advance and put on the books, thus making a grid of orders.
passivbot currently supports all Binance and Bybit futures markets. The script may be run from a local computer, but in most cases using a remote VPS is more convenient. For example, several bot instances may be run on a $5/month VPS without issue.
Included live configs are found in configs/live/name.json
config_name
Arbitrary name given to config
logging_level
Set to 0, no logging. Set to 1, logs positions, open orders, order creations, order cancellations to logs/{exchange}/{config_name}.log
min_span/max_span/n_spans
Bot uses exponential moving averages EMAs to limit entries and stop losses.
EMAs are not based on OHLCVs, but on raw trades, or "ticks"
EMA is defined as
ema = prev_ema * (1 - alpha) + tick_price * alpha
where
alpha = 2 / (span + 1)
Fastest EMA is given by min_span, slowest EMA is given by max_span, and n_spans gives how many EMAs.
long/shrt
Config parameters for long and short are separated.
enabled
Set to false to disable long/shrt
all MAr_coeffs
Selected parameters may be modified by ratios between EMAs of different spans.
Set to 0.0 to disable parameter modification by EMA ratios.
More details may come later.
iqty_const
Initial quantity percentage of balance.
Initial entry quantity is defined as balance_ito_contracts * iqty_const
E.g. if balance is $200 and iqty_const = 0.03
, cost of initial entry will be at least 200 * 0.03 == $6
iprc_const
An upper and a lower band of EMAs are made by taking min(EMAs) and max(EMAs), respectively.
Initial long entry price is lower_EMA_band * iprc_const
and initial shrt entry price is upper_EMA_band * iprc_const
For example, if EMAs = [33.4, 32.1, 32.9]
, upper band is 33.4 and lower band is 32.1.
If shrt_iprc_const = 1.005, shrt_entry_price = 33.4 * 1.005 == 33.567
rqty_const
Reentry quantity is initial entry quantity plus position size times rqty_const.
For example, say psize is 10.0, rqty_const is 1.2 and initial entry qty is 2.2 (see iqty_const).
Then reentry qty is 2.2 + 10.0 * 1.2 == 14.2.
rprc_const
Long reentry price is min(initial_long_entry_price, long_position_price * long_rprc_const)
Short reentry price is max(initial_shrt_entry_price, shrt_position_price * shrt_rprc_const)
PBr_coeffs
This parameter's purpose is to increase spacing between reentries in proportion to position size.
The ratio of position cost to balance times PBr_coeffs is added to rprc_const.
Say psize is 0.23, pprice is 250.0 and balance is 80.0. Position cost is 0.23 * 250.0 = 57.5 and PBr is position_cost / balance == 57.5 / 80 == 0.71875.
The formula is rprc_modifier = pbr**2 * PBr_coeffs[0] + pbr * PBr_coeffs[1]
Say long rprc_const = 0.98 If PBr_coeffs is (-0.05, 0.01), rprc = rprc_const + 0.71875**2 * -0.05 + 0.71875 * 0.01 == 0.98 + -0.018642578125000003 == 0.961357421875
So next long reentry will be ~3.86% instead of 2.0% lower than long pprice.
markup_const
Bot closes entire position at static position_price * markup_const
pbr_limit
pbr is position_cost / balance
, where position_cost is position_size / position_price if inverse, otherwise position_size * position_price
A position's cost may not be greater than pbr_limit + pbr_stop_loss.
pbr_stop_loss
Specifies how much a position's cost may overstep its pbr_limit.
Bot will partially close position at a loss if position_cost / balance is greater than pbr_limit.
exchange
binance or bybit
user
set your account name here, needed to fetch ticks
symbol
symbol to backtest. note differences between USDT margined symbols (ends with USDT) and inverse symbols (ends with USD). also note difference between binance inverse perpetual and inverse futures (e.g. ETHUSD_PERP or ETHUSD_210625)
latency_simulation_ms
simulate latency between bot and exchange
starting_balance
starting balance in margin token (USDT in linear markets, coin in inverse markets)
start_date/end_date
timeframe to backtest
pso options
particle swarm optimization options
iters: n backtests
num_cpus: max n cpus for parallel testing
options: c1, c2, w. pso specific options, see for example https://pymoo.org/algorithms/pso.html for more info
n_particles: n particles, see above link for more info
minimum_bankruptcy_distance
optimizer will penalize configs whose bankruptcy in backtests came closer than given threshold
minimum_equity_balance_ratio
optimizer will penalize configs whose equity / balance ratio in backtests came closer than given threshold
minimum_slice_adg
more info may be added
max_n_hours_between_fills
optimizer will penalize configs whose max duration between consecutive fills in backtest was higher than given threshold
ranges
search space for each tunable parameter. if min and max are equal, parameter is fixed and not tuned.