# Recharging Tranche Strategy
## Introduction
The recharging tranche strategy offers a firm price for batches of tokens via a publicly visible and continual spread backed with real liquidity. Each individual batch of tokens is referred to as a "tranche".
Aggregated, these tranches form a stepped price curve:
- A sell curve can be used to liquidate treasury or to help even out spikes in the market price by offering additional liquidity.
- A buy curve can be used to "buy the dip" or become a buyer of last resort at decreasing prices.
When the market price moves into or past a tranche, an arbitrage opportunity is created, causing tokens in the tranche to clear. Each time a batch of tokens fully clears, a new batch is made available in the next tranche. Tranches can partially or fully clear, and multiple tranches can clear in a single trade.
<figure>

<figcaption>Tranche-Space Strategy: Visual representation of the tranche curve where the y-axis indicates the price and the x-axis indicates the tranche number. The curve demonstrates how the recharging tranche strategy functions for both buying and selling.</figcaption>
</figure>
### Similarity to grid strategies
This strategy shares similarities with a traditional [grid strategy](https://www.investopedia.com/terms/g/grid-trading.asp), which involves placing a series of buy and sell orders at predefined intervals above and below a set price.
For example, in the traditional forex market, a trader decides to use a grid strategy for EUR/USD, with the current price at 1.2000. The trader sets up buy orders at 1.1950, 1.1900, and 1.1850, and sell orders at 1.2050, 1.2100, and 1.2150. Each order size is 1,000 units. As the market moves, these orders get filled, allowing the trader to profit from price movements.
The key difference to the Recharging Tranche Strategy (apart from the fact it's onchain and completely algorithmic) is that it "recharges". This means that unlike a grid strategy, where each order is filled only once, each tranche will continually make more tokens available over time.
Importantly, the tranches recharge in order back to the starting point, ie if a higher sell tranche continues to clear out as it recharges, the lower priced tranches will not offer any tokens. This allows the strategy to "track" and dynamically respond to the market.
## When would you use this strategy?
### As a trader
- Trading in a volatile market within a range.
- Increasing TKN holdings by offering a spread that cycles through peaks and troughs.
> Example: A trader in the cryptocurrency market notices that Bitcoin (WBTC) experiences significant price volatility within a range of $45,000 to $50,000. Using the recharging tranche strategy, the trader sets the highest buy tranche at $47,000 and the lowest sell tranche at $48,000. Each tranche contains 0.1 WBTC, and the price of each subsequent tranche increases by $500 for sells and decreases by $500 for buys. As the market fluctuates, these tranches allow the trader to buy WBTC when the price drops to $47,000 or lower and sell WBTC when the price rises to $48,000 or higher, continually capitalizing on market movements within this range.
### As a market maker
- Liquidate tokens above a target price, provide buy support below.
- Continuously offer liquidity within a specific price band.
- Adjust liquidity based on price movements.
- Cease liquidity provision within a specified price range.
> Example: A market maker wants to provide liquidity for a Gold-backed token (GLD) within the $1,800 to $1,900 range. The highest buy tranche is set at $1,820 and the lowest sell tranche at $1,880. Each tranche contains 10 GLD, with the price of subsequent sell tranches increasing by $10 and buy tranches decreasing by $10. This setup allows the market maker to buy GLD when the price drops to $1,820 or lower and sell GLD when the price rises to $1,880 or higher, providing continuous liquidity and profiting from the spread.
### As a token issuer
- Build treasury by liquidating tokens above a target range.
- Act as a buyer of last resort below a specific range.
- Buy or sell tokens in varying amounts as the price fluctuates.
> Example: A new decentralized finance (DeFi) project issues its own token (DFT) and wants to manage its treasury. The issuer sets the highest buy tranche at $1.80 and the lowest sell tranche at $2.20, with each tranche containing 1,000 DFT. The price of each subsequent sell tranche increases by $0.10 and each buy tranche decreases by $0.10. This allows the project to sell tokens when the price exceeds $2.20 and buy tokens back when the price drops below $1.80, ensuring continuous market participation and maintaining token liquidity.
## Variants and control levers
Almost everything about the strat is parameterized and chartable, e.g.
* The algorithms that determine the price and amount of each tranche
* The recharge rate and delay before the passive recharge starts to kick in
* Whether the amounts per tranche are denominated in the input or output token
* Whether the strategy is buying or selling TKN
* An optional conversion between the input/output token and some external price, e.g. converting WETH in a vault to USD equivalent.
You'll see these options in the strategy YAML frontmatter.
### Growth curve
The growth curves can govern the amount of tokens in each tranche as well as the price jump between each tranche.
These can be:
- **Linear** - same differential between tranches
- **Exponential** - differential grows each tranche.
### Start price
Every tranche curve has a price for the first tranche, either:
- The lowest price in a sell curve, where subsequent tranches will be at ever higher prices
- The highest price in a buy curve, where subsequent tranches will be at ever lower prices
### Start tranche
Regardless of where the curve starts, when deploying the strategy you may decide to "initialise" at some tranche >1.
Consider a sell curve where the price for the first tranche is $1, and each tranche increases linearly by 10c, e.g. the 5th tranche will be priced at $1.50.
If the market is currently sitting at $1.57, when you deploy the strategy it's likely the first 5 tranches would immediately clear ($1.10, $1.20 etc), as all of those tranches are making an offer below the market and there is a clear arbitrage opportunity.
To deal with this undesirable outcome we can initialise the strategy in the 6th tranche, or in other words, we can initialise the strategy as if tranches 1-5 have already cleared.
### Recharge rate
The recharge rate is defined by how many tranches we move through in a second. For the purposes of the rate, 1e18 is one tranche.
For example, to recharge tranches once per day:
```
seconds in a day = 60 * 60 * 24 = 86400
recharge rate = 1e18 / 86400 = 11574e9
```
What does this mean in practice? Consider the example above, where we have initialised our strategy in tranche 6, which means we have tokens available for $1.60. The market starts at $1.57, and for the first 24 hours it hovers at that value, edging up to just under $1.60.
Tranches always recharge **in order** back to the first tranche, so immediately tranche 5 starts to recharge (ignore the delay for now, explained below).
This means that over the course of the day, as that tranche recharges, there will be arbitrage opportunites and we'll see a full tranche of tokens clear at $1.50.
### Recharge delay
After a trade occurs, there is a delay before the next tranche starts recharging. This delay serves two primary purposes:
- Market Feedback: This allows the market to absorb and react to the recent trade, helping to determine if the price adjustment from the trade needs to be sustained or if it was an anomaly. By observing the market's response, the strategy can adapt and potentially offer the next tranche at a different price before resetting to the previous setup.
- Dynamic Pricing: The pause enables the strategy to offer the next tranche at a different price, adapting to market conditions. This dynamic approach can capture better trading opportunities and enhance the effectiveness of the strategy.
However, the delay must be balanced:
- Too Long: If the delay is excessive, it could be exploited by market participants who aim to halt the recharging process, creating a stagnant market.
- Too Short: A very short delay might lead to rapid transitions between tranches, making it difficult for the market to stabilize and for the strategy to effectively track price movements.
The default delay is set to 5 minutes (300 seconds), which generally provides a good balance between observing market reactions and maintaining fluid trading.
### Shy liquidity
When a tranche is fully cleared, the strategy may introduce the next tranche partially, a concept known as "shy liquidity." Here’s how it works:
- Partial Activation: Instead of immediately offering the full amount of the next tranche, a fraction is made available. For example, if tranches are set to be 90% shy (i.e., 9e17), clearing a tranche completely will start the next tranche at 10% of its maximum size. This gradual introduction helps manage liquidity more efficiently.
- Capital Efficiency: By only partially activating the next tranche, the strategy reduces the capital requirements needed to adjust prices as the market moves.
Shyness Setting: The shyness parameter can be adjusted:
- Non-zero Shyness: If set to a value less than 1e18, it ensures that only a portion of the tranche is initially available. For example, with 90% shyness, only 10% of the next tranche is activated upon clearing the previous one.
- Zero Shyness: If set to 0, each tranche will be fully available as soon as it is entered.
It’s important to note that shyness must be less than 1e18 to avoid skipping tranches entirely.
## Parameters
At the time of writing, specific variables that can be configured in [tranche-space.rain](https://github.com/rainlanguage/rain.dex.pubstrats/blob/main/src/tranche-space.rain) are below.
| **Parameter Name** | **Description** |
|----------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `tranche-space-per-second` | The amount of tranche space that is recharged per second as a normalized 18 decimal fixed point value. |
| `tranche-space-recharge-delay` | The duration in seconds that no recharging occurs after a trade happens, allowing the market to stabilize and adapt to the recent trade. |
| `tranche-size-expr` | The expression to calculate the tranche size for the current tranche space. |
| `tranche-size-base` | The base tranche size, which is the size of the smallest tranche, denominated in the output token. |
| `tranche-size-growth` | The exponential growth factor of the tranche size, represented as a decimal 18 fixed point number (e.g., 1e16 represents 1% growth per tranche). |
| `io-ratio-expr` | The expression to calculate the input/output ratio (IO ratio) for the current tranche space. |
| `io-ratio-base` | The base IO ratio, represented as a decimal 18 fixed point number, which applies at tranche space 0 and grows according to the growth factor per tranche. |
| `io-ratio-growth` | The exponential growth factor of the IO ratio, represented as a decimal 18 fixed point number (e.g., 1e16 represents 1% growth per tranche). |
| `reference-stable` | The stable token used as a reference for the TWAP to offer dollar-equivalent conversions. |
| `reference-stable-decimals` | The number of decimals of the reference stable token. |
| `reference-reserve` | The token used to compare against the reference stable token to calculate the TWAP for dollar-equivalent conversions. |
| `reference-reserve-decimals` | The number of decimals of the reserve token. |
| `twap-duration` | The duration in seconds of the TWAP window for dollar-equivalence conversions. |
| `twap-fee` | The Uniswap fee tier to use for the TWAP. |
| `min-tranche-space-diff` | The minimum tranche space difference allowed per trade, represented as a decimal 18 fixed point number. Prevents dusting the strategy to stop it from recharging. |
| `tranche-space-snap-threshold` | The threshold in tranche space to snap to the nearest tranche, avoiding dust issues at the edges. |
| `initial-tranche-space` | The initial tranche space when the order is first deployed. |
| `get-last-tranche` | The binding to get the last tranche space and update time. |
| `set-last-tranche` | The binding to set the last tranche space and update time. |
| `tranche-space-shyness` | The shyness of the liquidity in tranches, as a decimal 18 fixed point number. For example, 9e17 represents 90% shyness. |
| `test-tranche-space-before` | The value returned by `get-test-last-tranche` to allow the tranche space before to be bound for testing. |
| `test-last-update-time` | The value returned by `get-test-last-tranche` to allow the last update time to be bound for testing. |
| `test-now` | The value returned by `get-test-last-tranche` to allow the current time to be bound for testing. |
| `io-ratio-multiplier` | The binding to get the IO ratio multiplier. |
| `amount-is-output` | Indicates whether the amount is an output or input amount. Non-zero means output (i.e., normal orderbook behavior), zero means input. |
| `plottables` | The binding for additional items to plot during testing. |
| `uniswap-words` | The subparser for the Uniswap words. |
| `orderbook-subparser` | The subparser for the orderbook. |
| `plottables-test` | Additional plottables for testing scenarios, including amount, IO ratio, input amount, and effective price. |
| `plottables-prod` | Additional plottables for production scenarios, including amount and IO ratio. |
# Tutorial
Use the [recharging tranche space strategy](https://github.com/rainlanguage/rain.dex.pubstrats/blob/main/src/tranche-space.rain).
## Example strategy wFLR / eUSDT
In this strategy I sell wFLR when it is greater than $0.03 and buy when it is less than $0.03 and I can set increasing sell/buy sizes as the price diverges from the starting point.
This is a great treasury management or token management strategy for believers in Flare.
### Market conditions
The strategy works well while the token price is initially ranging around $0.03 and I've got capital to deploy or tokens to liquidate as it diverges significantly.
### Network parameters
First I go to Raindex pubstrats and fork the [tranche space strategy](https://github.com/rainlanguage/rain.dex.pubstrats/blob/main/src/tranche-space.rain).
Then I enter the network details, in this case Flare. I label each parameter so these don't conflict with my app settings.
```
networks:
flare-tranche:
rpc: https://rpc.ankr.com/flare
chain-id: 14
network-id: 14
currency: FLR
subgraphs:
flare-tranche: https://subgraphs.h20liquidity.tech/subgraphs/name/flare-0xb06202aA
orderbooks:
flare-tranche:
address: 0xb06202aA3Fe7d85171fB7aA5f17011d17E63f382
network: flare-tranche
subgraph: flare-tranche
deployers:
flare-tranche:
address: 0x550878091b2B1506069F61ae59e3A5484Bca9166
network: flare-tranche
tokens:
flare-wflr:
network: flare-tranche
address: 0x1D80c49BbBCd1C0911346656B529DF9E5c2F783d
flare-eusdt:
network: flare-tranche
address: 0x96B41289D90444B8adD57e6F265DB5aE8651DF29
```
### Token Parameters
Then I enter tokens I want to trade. In this case it's wFLR and eUSDT. I get the contract address either from the Raindex pubstrats or from [Flarescan](https://flarescan.com/). Note I can have a basket of tokens not just a pair.
```
tokens:
flare-wflr:
network: flare-tranche
address: 0x1D80c49BbBCd1C0911346656B529DF9E5c2F783d
flare-eusdt:
network: flare-tranche
address: 0x96B41289D90444B8adD57e6F265DB5aE8651DF29
```
### Orders & Vaults
I put up my buy and sells with the relevant orderbook and my vaults. I can deposit and withdraw tokens into this vault after my order is deployed.
```
orders:
# vault-id generated with `openssl rand -hex 32`
flare-tranche-buy:
orderbook: flare-tranche
inputs:
- token: flare-wflr
vault-id: 0x562bd75e19e548420f9f3da43a7d7d67c6344580256b952c9214192c445d6043
outputs:
- token: flare-eusdt
vault-id: 0x562bd75e19e548420f9f3da43a7d7d67c6344580256b952c9214192c445d6043
flare-tranche-sell:
orderbook: flare-tranche
inputs:
- token: flare-eusdt
vault-id: 0x562bd75e19e548420f9f3da43a7d7d67c6344580256b952c9214192c445d6043
outputs:
- token: flare-wflr
vault-id: 0x562bd75e19e548420f9f3da43a7d7d67c6344580256b952c9214192c445d6043
```
### Scenarios
I set up the parameters that are consistent across both buy and sell scenarios. This is scriptable. These include:
* Subparser details
* How many seconds a tranche space lasts for
* Tranche space recharge delay
* Tranche space shyness
* Minimum trade size (diff)
* Snap threshold
* IO ratio multiplier
```
scenarios:
flare-tranche-tranches:
network: flare-tranche
deployer: flare-tranche
orderbook: flare-tranche
bindings:
uniswap-words: 0xb1d6D10561D4e1792A7c6B336b0529e4bFb5Ea8F
orderbook-subparser: 0xF836f2746B407136a5bCB515495949B1edB75184
tranche-space-per-second: 11574074074074
tranche-space-recharge-delay: 300
tranche-space-shyness: 9e17
min-tranche-space-diff: 1e17
tranche-space-snap-threshold: 1e16
io-ratio-multiplier: '''io-ratio-multiplier-identity'
```
### Buy scenarios
Specific scenarios for buying wFLR including base price, growth rates for tranche prices, tranche amounts and growth rates. Here we also define the simulations and later the chart details.
```
scenarios:
buy:
bindings:
amount-is-output: 1
io-ratio-expr: '''linear-growth'
io-ratio-base: 33e18
io-ratio-growth: 3e18
tranche-size-expr: '''linear-growth'
tranche-size-base: 10e18
tranche-size-growth: 1e18
scenarios:
initialized:
bindings:
initial-tranche-space: 0
scenarios:
prod:
bindings:
get-last-tranche: '''get-last-tranche-prod'
set-last-tranche: '''set-last-tranche-prod'
plottables: '''plottables-prod'
test:
runs: 100
bindings:
get-last-tranche: '''get-last-tranche-test-init'
set-last-tranche: '''set-last-tranche-test'
plottables: '''plottables-test'
test-last-update-time: 0
test-now: 0
test:
runs: 10000
bindings:
get-last-tranche: '''get-last-tranche-test'
set-last-tranche: '''set-last-tranche-test'
plottables: '''plottables-test'
max-test-tranche-space: 20e18
test-last-update-time: 0
test-now: 0
```
### Buy deployment visualisation
The first chart section tells us viusally what our strategy is doing. Here it is showing me that:
1. I will be spending $10 buying FLR in the first tranche
2. With a FLR per USD of 33 (or a Flare price of $0.0303)
3. Which means I buy 330 FLR in the first tranche ($10 tranche with 33 tokens per $1)
4. Strategy will start at the first tranche

This aligns with my expectations which means I can move forward.
### Buy charts simulation
The second chart section tells us visually what our strategy is doing based on running simulations on my device. We fork the blockchain and then simulate according to the parameters in the strategy. Here we can see we've selected 10,000 simulations with a max tranche space of 20, so we only simulate 20 tranches.
The first chart shows us that we purchase 330 FLR in the first tranche, and then that we increase the amount of FLR per tranche, purchasing approx 2,500 FLR at tranche 20.
The second chart (io-ratio) shows the number of FLR purchased per USD spent, which also increases in a stepwise fashion as designed.
The third chart shows that we spend an increasing amount of USD per tranche, which makes sense as we want to buy more FLR as the market drops.
The fourth chart shows the price we are paying for 1 FLR in USD, which shows a decrease in price per FLR as our tranches increase.
The fifth chart shows our starting tranche:

### Sell scenarios
Specific scenarios for selling wFLR including base price, growth rates for tranche prices, tranche amounts and growth rates. Here we also define the simulations and later the chart details.
```
sell:
bindings:
amount-is-output: 0
io-ratio-expr: '''linear-growth'
io-ratio-base: 3e16
io-ratio-growth: 1e16
tranche-size-expr: '''linear-growth'
tranche-size-base: 10e18
tranche-size-growth: 1e14
scenarios:
initialized:
bindings:
initial-tranche-space: 1e18
scenarios:
prod:
bindings:
get-last-tranche: '''get-last-tranche-prod'
set-last-tranche: '''set-last-tranche-prod'
plottables: '''plottables-prod'
test:
runs: 100
bindings:
get-last-tranche: '''get-last-tranche-test-init'
set-last-tranche: '''set-last-tranche-test'
plottables: '''plottables-test'
test-last-update-time: 0
test-now: 0
test:
runs: 10000
bindings:
get-last-tranche: '''get-last-tranche-test'
set-last-tranche: '''set-last-tranche-test'
plottables: '''plottables-test'
max-test-tranche-space: 20e18
test-last-update-time: 0
test-now: 0
```
### Sell deployment visualisation
The first chart section tells us viusally what our strategy is doing. Here it is showing me that:
1. I will be selling 333 FLR in the first tranche
2. And I receive $10 USD for the sales
3. Which means my effective sell price is 0.03
4. Strategy will start at the first tranche

Again this lines up with my expectations.
### Sell charts simulation
The sell chart simulation is the same as the buy chart simulation, except that it covers selling, not buying wFLR.
The first chart shows our starting tranche.
The second chart (io-ratio) shows the number of FLR sold per USD spent which also increases in a stepwise fashion as designed. Here we are selling more FLR per USD as the FLR price increases.
The third chart shows that we spend the same USD per tranche. We may also consider a strategy where we sell more USD per tranche as tranches increase either linearly or exponentially.
The fourth chart is the same as io-ratio, and shows our effective price per tranche.
The fifth chart shows the number of FLR we sell per tranche.

### Checking it executes live
Using Raindex I added the orders and then funded the vault.
You can see the orders:
0x5259dd5154f7d8478cb395cd5b7c2e574384ded28872712a185336e2e2f84915
0x8f5fd9e9ea6015d9939818828184ee9811ca10035cf28e71d64b17a79022102c
## Extending your tranche space strategy
Users can put in a minimum trade size, if you put in a trade for less than x% of a tranche it wont clear, which mitigates people pinging strat for dust orders to stop recharging.
Tranches can also be snapped to the nearest tranche to avoid dust issues at the edges, either due to rounding in the EVM or potentially malicious trades.
This is only relevant if the tranche size/ratio is denominated in some token other than the input/output tokens. For example, if the TKN was being traded for WETH but the tranche size was denominated in USD, the reference-stable would be USD and the reference-reserve would be WETH, and the identity multiplier needs to be swapped out for e.g. a TWAP USDT based multiplier. Typically this is not needed, as the tranche size and ratio are denominated in the input/output tokens.
## Publishing
6 May 2024
David Atkinson
Version 1.0