terra-revival / backtest

Python backtesting engine for USTC or any Terra Classic Stable Algos
Other
6 stars 2 forks source link

#4 Divergence protocol initial implementation #25

Closed Kyjaque closed 10 months ago

Kyjaque commented 11 months ago

Use run.py, to run the simulations, it is outside of main directory, it should open browser windows with charts

adding/fixing:

RedlineDrifter commented 11 months ago

strategy.py -- check line 62

Kyjaque commented 11 months ago

Simple usage

Minimum code to run sims and display results:

some predefined constants used # basic vars used to create market base_pair, quote_pair = "USTC/BUSD", "USDT/BUSD" liquidity_usd = 1000000 ust_start_price = 0.1 binance_swap_fee = 0.12 / 100

  1. get simulated functions (predefined) sims = simulationSamples(42, False, 365 6 2) alternative is your own dictionary in the format of. key is the name of the function, data is array of floats (prices), timeframe in seconds prices={"wild brownian": {"data": X, "timeframe": timeframe}, ...}
  2. pick simulation divergence parameters div_protocol_args = { "soft_peg_price": ust_start_price, # start right at the peg price, seems a smart decision # after we reach final peg 1$, this ratio of tax is left for arb traders to keep. 0 = we tax 100% of divergence "arbitrage_coef": 0.05, # when at peg $1, we tax this ratio less to allow arbitrage "cex_tax_coef": 0.001, # ratio of how much tax CEX gets # not used yet, we are not clear if to buyback with all the tax or keep base token also. 1 = spend all base tokens "buy_backs_coef": 1, "timeframe": 3600 * 4, # time difference between 2 price points of inputs in seconds, makes up axis X on charts. tied to steps in simulationSamples "start_date": datetime.now(), # start date of axis X "swap_pool_coef": 0.475, # ratio how much of tax goes to the swap pool "staking_pool_coef": 0.475, # ratio how much of tax goes to the staking pool "oracle_pool_coef": 0.025, # ratio how much of tax goes to the oracle pool "community_pool_coef": 0.025, # ratio how much of tax goes to the community pool # soft peg related increase variables "soft_peg_increase": 0.1, # how much is softpeg raised in 1 step "soft_peg_moving_window": 10, # moving average window length used for price }
  3. run sim for each of the price functions and display results for sim in sims: # we do a deep copy to start each simulation with original market state # use_market = copy.deepcopy(mkt) base = MarketQuote(base_pair, ust_start_price) quote = MarketQuote(quote_pair, 1) mkt = new_market(liquidity_usd, quote, base, binance_swap_fee)

    # run first with buybacks use_args = copy.deepcopy(div_protocol_args) use_args["do_buybacks"] = True amm = ConstantProductEngine(mkt) div_strategy = DivStrategy(amm, use_args) # instantiate div strategy class simul = peg_simulation(sims[sim], div_strategy, use_args, "avg") # run the simulation, returned are trades with all data

    # now run without buybacks, this is optional, if you want to overlay in1 chart ust price with and without buybacks use_args = copy.deepcopy(div_protocol_args) use_args["do_buybacks"] = False amm = ConstantProductEngine(mkt) div_strategy = DivStrategy(amm, use_args) simul_nobuyback = peg_simulation(sims[sim], div_strategy, use_args, "avg")

    # add no buyback price to the simulation simul["breakdown"]["mkt_price_nbb"] = simul_nobuyback["breakdown"].mkt_price

    simul["sim_name"] = sim # display results show(new_simulation_figure(mkt, simul))

Kyjaque commented 11 months ago

Inner logic

peg_simulation

  1. run one of the softpeg increase, either 'time' or 'avg'. time based splits the sim function into N equal steps between start peg price and 1, step increase is in the params as args["soft_peg_increase"] avg based calculates a moving window of ust price and if it is above the current peg, it is increased by args["soft_peg_increase"]
  2. for all price points in the simulated function, calculate the % gain between current and next price rel_gain = (function[idx + 1] - function[idx]) / function[idx]
  3. calculate how much ust to buy or sell to move the price the same gain as calculated in step 2
  4. run the trade by calling strategy.execute_div, return value is array of trades
  5. calculate the sum of taxes collected
  6. if sum > 0 and param args["do_buybacks"] is set to true, and we are not at final peg args["soft_peg_price"] < 1, do a buyback by calling strategy.execute_div again, with the difference we dont tax this trade
  7. if we did any buyback, spread the UST into 4 pools

DivStrategy class has all the crucial methods

calc_taxes, args of price and volume, returns the taxed amount in USDT based on current peg time_peg_increase is moving the peg in time steps avg_price_peg_increase is moving the peg price wise execute_div executes a trade, args are market price, TradeOrder, datetime of the trade, flag if it is a buyback

  1. updates the market with self.cp_amm.update_mkt_price(mkt_price)
  2. executes the trade executed = self.cp_amm.execute_trade(current_row, trade_order)
  3. calculates the tax by calling calc_taxes
  4. if we have tax, split it between CEX anc CHAIN args["cex_tax_coef"] is the portion how much a cex gets, rest is chain
  5. return all the trade info
Kyjaque commented 10 months ago

closing cause of future code reset from faffy