Tags: bollinger-bands, mean-reversion, advanced, shorting, stop-loss, leverage, ema, rsi

Long & Short direction mean reversion strategy with Bollinger Bands, Uniswap v3 on Polygon#

This strategy introduces the new shorting capabilities of the TradingStrategy framework. Shorting allows us to profit on downturns in the market, so now, if we trade correctly, it is possible to earn profit whether the market is going up or down.

Shorting#

For those of you who aren’t familiar with shorting, here is a quick explanation:

Short selling, often referred to as “shorting,” is an investment strategy where an investor borrows shares of a stock or other asset that they believe will decrease in value by a set future date. The investor sells these borrowed shares to buyers willing to pay the current market price. Later, the investor aims to buy back the shares at a lower price.

However, short selling comes with significant risks. If the stock price increases instead of decreasing, the investor will have to buy back the shares at a higher price, leading to a loss. This loss can be substantial, as theoretically, a stock’s price can rise indefinitely. That’s why is important to always use a stop loss with shorting.

Short selling is often used as a way to hedge against the downside risk of a long position in the same or similar stocks. It can also be used by those who believe the market or a particular stock is overvalued and due for a downturn.

Leverage#

Leverage refers to the use of various financial instruments or borrowed capital (like debt) to increase the potential return of an investment. It allows investors to increase their market exposure beyond what would be possible with their own capital alone. Basically, leverage amplifies investment power; however, leverage also amplifies losses if the investment does not perform as expected. Since the investor must repay the borrowed funds regardless of the investment’s success, losses can exceed the initial amount of capital. So again, remember your stop losses!

Set up#

Set up the parameters used in in this strategy backtest study.

  • Backtested blockchain, exchange and trading pair

  • Backtesting period

  • Strategy parameters

[1]:
import datetime
import pandas as pd

from tradingstrategy.chain import ChainId
from tradingstrategy.timebucket import TimeBucket
from tradingstrategy.lending import LendingProtocolType  # NEW
from tradeexecutor.strategy.cycle import CycleDuration
from tradeexecutor.strategy.strategy_module import StrategyType, TradeRouting, ReserveCurrency

# Tell what trade execution engine version this strategy needs to use
# NOTE: this setting has currently no effect
TRADING_STRATEGY_TYPE_ENGINE_VERSION = "0.1"

# What kind of strategy we are running.
# This tells we are going to use
# NOTE: this setting has currently no effect
TRADING_STRATEGY_TYPE = StrategyType.managed_positions

# How our trades are routed.
TRADE_ROUTING = TradeRouting.uniswap_v3_usdc

# How often the strategy performs the decide_trades cycle.
# We do it for every 4h.
TRADING_STRATEGY_CYCLE = CycleDuration.cycle_4h

# Strategy keeps its cash in USDC
RESERVE_CURRENCY = ReserveCurrency.usdc

# Time bucket for our candles
CANDLE_TIME_BUCKET = TimeBucket.h4

# Which trading pair we are backtesting on
TRADING_PAIR = (ChainId.polygon, "uniswap-v3", "WETH", "USDC", 0.0005)

# Which lending reserves we are using for supplying/borrowing assets
# NEW
LENDING_RESERVES = [
    (ChainId.polygon, LendingProtocolType.aave_v3, "WETH"),
    (ChainId.polygon, LendingProtocolType.aave_v3, "USDC"),
]

# How much % of the cash to put on a single trade
POSITION_SIZE = 0.8

# Start with this amount of USD
INITIAL_DEPOSIT = 50_000

# Candle time granularity we use to trigger stop loss checks
STOP_LOSS_TIME_BUCKET = TimeBucket.h1

#
# Strategy thinking specific parameter
#

# How many candles we load in the decide_trades() function for calculating indicators
LOOKBACK_WINDOW = 50

# Moving average
# How many candles to smooth out for Bollinger band's middle line
EMA_CANDLE_COUNT = 20


# How many candles we use to calculate the Relative Strength Indicator
RSI_LENGTH = 14

# RSI must be above this value to open a new Long position
RSI_THRESHOLD = 35

# RSI must be above this value to open a new Short position
RSI_THRESHOLD_SHORT = 70

# Backtest time range: start date
START_AT = datetime.datetime(2022, 7, 20)

# Backtest time range: end date
END_AT = datetime.datetime(2023, 9, 27)


# A fixed Stop Loss for Long positions relative to the mid price during the time when the position is opened
# If the price candle closes below this level in a Long position, stop loss gets triggered
STOP_LOSS_PCT = 0.97

# A fixed Stop Loss for Short positions relative to the mid price during the time when the position is opened
# If the price candle closes above this level in a Short position, stop loss gets triggered
STOP_LOSS_SHORT_PCT = 0.97

# Take profit percentage for Long positions
TAKE_PROFIT_PCT = 1.035

# Take profit percentage for Short positions
TAKE_PROFIT_SHORT_PCT = 1.035

# Leverage ratio for short positions. We use leverage that is hogher than 1, because lending pools require more collateral than the amount that you want to borrow
LEVERAGE = 2

Strategy logic and trade decisions#

In this example, we calculate two exponential moving averages (EMAs) and make decisions based on those:

  • enter Long positions when price candle closes below the lower BB line

  • enter Short position when price candle closes above the higher BB line

  • use RSI value as threshold and additional confluence when deciding trade entries

  • 4 hour price candle time frame for price action analysis and trade entries

  • use a fixed % based stop loss with 1 hour price candle time frame

  • enable Short positions by using Aave v3 lending pools for borrowing the token that you want to short sell

Indicators#

  • Note how we also make use of detached and overlayed technical indicators, so that the price chart is not overcrowded

[2]:
from typing import List, Dict

from pandas_ta import bbands
from pandas_ta.overlap import ema
from pandas_ta.momentum import rsi

from tradingstrategy.universe import Universe
from tradeexecutor.strategy.trading_strategy_universe import TradingStrategyUniverse

from tradeexecutor.state.visualisation import PlotKind
from tradeexecutor.state.trade import TradeExecution
from tradeexecutor.strategy.pricing_model import PricingModel
from tradeexecutor.strategy.pandas_trader.position_manager import PositionManager
from tradeexecutor.state.state import State
from tradeexecutor.strategy.pandas_trader.position_manager import PositionManager


def decide_trades(
        timestamp: pd.Timestamp,
        strategy_universe: TradingStrategyUniverse,
        state: State,
        pricing_model: PricingModel,
        cycle_debug_data: Dict) -> List[TradeExecution]:

    universe = strategy_universe.universe

    # We have only a single trading pair for this strategy.
    pair = universe.pairs.get_single()

    # How much cash we have in a hand
    cash = state.portfolio.get_current_cash()

    # Get OHLCV candles for our trading pair as Pandas Dataframe.
    # We could have candles for multiple trading pairs in a different strategy,
    # but this strategy only operates on single pair candle.
    # We also limit our sample size to N latest candles to speed up calculations.
    candles: pd.DataFrame = universe.candles.get_single_pair_data(timestamp, sample_count=LOOKBACK_WINDOW)

    # We have data for open, high, close, etc.
    # We only operate using candle close values in this strategy.
    close_prices = candles["close"]

    # Calculate exponential moving for candle close
    # https://tradingstrategy.ai/docs/programming/api/technical-analysis/overlap/help/pandas_ta.overlap.ema.html#ema
    moving_average = ema(close_prices, length=EMA_CANDLE_COUNT)


    # Calculate RSI for candle close
    # https://tradingstrategy.ai/docs/programming/api/technical-analysis/momentum/help/pandas_ta.momentum.rsi.html#rsi
    current_rsi = rsi(close_prices, length=RSI_LENGTH)[-1]

    trades = []

    if moving_average is None:
        # Cannot calculate EMA, in case there are not enough data points in backtesting buffer yet.
        return trades


    # Price at the most recent candle close
    price_close = close_prices.iloc[-1]

    # Create a position manager helper class that allows us easily to create
    # opening/closing trades for different positions
    position_manager = PositionManager(timestamp, strategy_universe, state, pricing_model)



    # Calculate wider Bollinger Bands using the typical 20-day MA and 2 standard deviations
    bollinger_bands_wide = bbands(close_prices, length=20, std=2)
    wide_bb_upper = bollinger_bands_wide["BBU_20_2.0"]
    wide_bb_lower = bollinger_bands_wide["BBL_20_2.0"]

    ### LONGING
    if not position_manager.is_any_long_position_open():
        # We open long if the latest candle close is under the lower BB line, the previous candle close was above the lower BB line, and RSI is above the RSI threshold value
        if price_close < wide_bb_lower.iloc[-1] and candles["open"].iloc[-1] > wide_bb_lower.iloc[-1] and close_prices.iloc[-2] > wide_bb_lower.iloc[-2] and current_rsi > RSI_THRESHOLD:
            amount = cash * POSITION_SIZE
            new_trades = position_manager.open_1x_long(pair, amount, stop_loss_pct=STOP_LOSS_PCT, take_profit_pct=TAKE_PROFIT_PCT)
            trades.extend(new_trades)
    else:
        # LONGING: We close the position when the price closes above the moving average line.
        if price_close > moving_average.iloc[-1] and close_prices.iloc[-2] < moving_average.iloc[-2]:
            current_position = position_manager.get_current_long_position()
            new_trades = position_manager.close_position(current_position)
            trades.extend(new_trades)

    ### SHORTING
    if not position_manager.is_any_short_position_open():
        # We open Short position if the latest candle close is above the higher BB line, the previous candle close was below the higher BB line, and RSI is below the RSI threshold value
        if price_close > wide_bb_upper.iloc[-1] and close_prices.iloc[-2] < wide_bb_upper.iloc[-2] and current_rsi < RSI_THRESHOLD_SHORT:
            amount = cash * POSITION_SIZE
            new_trades = position_manager.open_short(pair, amount, leverage=LEVERAGE, stop_loss_pct=STOP_LOSS_SHORT_PCT, take_profit_pct=TAKE_PROFIT_SHORT_PCT)
            trades.extend(new_trades)
    else:
        # We close the position when the price closes below the moving average line.
        if price_close < moving_average.iloc[-1] and close_prices.iloc[-2] > moving_average.iloc[-2]:
            current_position = position_manager.get_current_short_position()
            new_trades = position_manager.close_position(current_position)
            trades.extend(new_trades)

    # Visualise our technical indicators
    visualisation = state.visualisation
    visualisation.plot_indicator(timestamp, "Wide BB upper", PlotKind.technical_indicator_on_price, wide_bb_upper.iloc[-1], colour="red")
    visualisation.plot_indicator(timestamp, "Wide BB lower", PlotKind.technical_indicator_on_price, wide_bb_lower.iloc[-1], colour="red")
    visualisation.plot_indicator(timestamp, "EMA", PlotKind.technical_indicator_on_price, moving_average.iloc[-1], colour="black")
    visualisation.plot_indicator(timestamp, "RSI", PlotKind.technical_indicator_detached, current_rsi)

    return trades

Defining the trading universe#

We create a trading universe with a single blockchain, single exchange and a single trading pair.

Trading Strategy framework supports complex strategies, spanning thousands of pairs and lending pools, but we are not interested in this example.

[3]:
import datetime
from tradingstrategy.client import Client
from tradeexecutor.strategy.trading_strategy_universe import TradingStrategyUniverse, load_partial_data
from tradeexecutor.strategy.execution_context import ExecutionContext
from tradeexecutor.strategy.universe_model import UniverseOptions


def create_single_pair_trading_universe(
        ts: datetime.datetime,
        client: Client,
        execution_context: ExecutionContext,
        universe_options: UniverseOptions,
) -> TradingStrategyUniverse:
    dataset = load_partial_data(
        client,
        execution_context=execution_context,
        time_bucket=CANDLE_TIME_BUCKET,
        pairs=[TRADING_PAIR],
        universe_options=universe_options,
        start_at=universe_options.start_at,
        end_at=universe_options.end_at,
        lending_reserves=LENDING_RESERVES,  # NEW
        stop_loss_time_bucket=STOP_LOSS_TIME_BUCKET,
    )

    # Filter down to the single pair we are interested in
    strategy_universe = TradingStrategyUniverse.create_single_pair_universe(dataset)

    return strategy_universe

Set up the market data client#

The Trading Strategy market data client is the Python library responsible for managing the data feeds needed to run the backtest.None

We set up the market data client with an API key.

If you do not have an API key yet, you can register one.

[4]:
from tradingstrategy.client import Client

client = Client.create_jupyter_client()
Started Trading Strategy in Jupyter notebook environment, configuration is stored in /home/alex/.tradingstrategy

Load data#

[5]:
from datetime import timedelta
from tradeexecutor.strategy.execution_context import ExecutionMode
from tradeexecutor.strategy.universe_model import UniverseOptions

universe = create_single_pair_trading_universe(
    END_AT,
    client,
    ExecutionContext(mode=ExecutionMode.data_preload),
    UniverseOptions(
        # NOTE: quick hack to get enough data for look back period
        start_at=START_AT - timedelta(days=50),
        end_at=END_AT,
    )
)
print(f"We loaded {universe.universe.candles.get_candle_count():,} candles.")
We loaded 2,681 candles.

Run backtest#

Run backtest using giving trading universe and strategy function.

  • Running the backtest outputs state object that contains all the information on the backtesting position and trades.

  • The trade execution engine will download the necessary datasets to run the backtest. The datasets may be large, several gigabytes.

[6]:
from tradeexecutor.backtest.backtest_runner import run_backtest_inline

state, universe, debug_dump = run_backtest_inline(
    name="BB short example",
    start_at=START_AT,
    end_at=END_AT,
    client=client,
    cycle_duration=TRADING_STRATEGY_CYCLE,
    decide_trades=decide_trades,
    universe=universe,
    initial_deposit=INITIAL_DEPOSIT,
    reserve_currency=RESERVE_CURRENCY,
    trade_routing=TRADE_ROUTING,
    engine_version="0.3",
)

trade_count = len(list(state.portfolio.get_all_trades()))
print(f"Backtesting completed, backtested strategy made {trade_count} trades")
Backtesting completed, backtested strategy made 136 trades

Examine backtest results#

Examine state that contains all actions the trade executor took.

We plot out a chart that shows - The price action - When the strategy made buys or sells

[7]:
print(f"Positions taken: {len(list(state.portfolio.get_all_positions()))}")
print(f"Trades made: {len(list(state.portfolio.get_all_trades()))}")
Positions taken: 68
Trades made: 136
[8]:

from tradeexecutor.visual.single_pair import visualise_single_pair, visualise_single_pair_positions_with_duration_and_slippage
from tradingstrategy.charting.candle_chart import VolumeBarMode

figure = visualise_single_pair(
    state,
    universe.universe.candles,
    start_at=START_AT,
    end_at=END_AT,
    volume_bar_mode=VolumeBarMode.separate,
    volume_axis_name="Volume (USD)",
    height = 1200,
)

figure.show()
[9]:
from tradeexecutor.backtest.notebook import setup_charting_and_output
setup_charting_and_output()


# Needed to improve the resolution of matplotlib chart used here
%config InlineBackend.figure_format = 'svg'

from tradeexecutor.visual.equity_curve import calculate_equity_curve, calculate_returns
from tradeexecutor.visual.equity_curve import visualise_equity_curve

curve = calculate_equity_curve(state)
returns = calculate_returns(curve)
visualise_equity_curve(returns)
/tmp/ipykernel_61373/746198727.py:1: DeprecationWarning:

This module is deprecated. Import tradeexecutor.utils.notebook instead

[9]:
../../_images/programming_strategy-examples_long-short-bollingerbands-polygon_19_1.svg

Benchmarking the strategy performance#

Here we benchmark the strategy performance against some baseline scenarios.

  • Buy and hold US dollar

  • Buy and hold the underlying trading pair base asset

[10]:
from tradeexecutor.visual.benchmark import visualise_benchmark

traded_pair = universe.universe.pairs.get_single()

fig = visualise_benchmark(
    "Example long & short mean reversion strategy",
    portfolio_statistics=state.stats.portfolio,
    all_cash=state.portfolio.get_initial_deposit(),
    buy_and_hold_asset_name=traded_pair.base_token_symbol,
    buy_and_hold_price_series=universe.universe.candles.get_single_pair_data()["close"],
    start_at=START_AT,
    end_at=END_AT,
    height=1200
)

fig.show()

Analysing the strategy success#

Here we calculate statistics on how well the strategy performed.

  • Won/lost trades

  • Timeline of taken positions with color coding of trade performance

[11]:
from tradeexecutor.analysis.trade_analyser import build_trade_analysis

analysis = build_trade_analysis(state.portfolio)

Strategy summary#

Overview of strategy performance

[12]:
from IPython.core.display_functions import display

summary = analysis.calculate_summary_statistics(state=state, time_bucket = CANDLE_TIME_BUCKET)

# with pd.option_context("display.max_row", None):
#      display(summary.to_dataframe())

summary.display()
Returns
Annualised return % 41.62%
Lifetime return % 48.43%
Realised PnL $27,864.04
Unrealised PnL $0.00
Trade period 424 days 16 hours
Holdings
Total assets $74,213.29
Cash left $74,213.29
Open position value $0.00
Open positions 0
Winning Losing Total
Closed Positions
Number of positions 49 19 68
% of total 72.06% 27.94% 100.00%
Average PnL % 2.05% -3.29% 0.56%
Median PnL % 1.74% -3.36% 1.35%
Biggest PnL % 4.88% -5.44% -
Average duration 1 days 1 hours 1 days 10 hours 1 days 4 hours
Max consecutive streak 13 4 -
Max runup / drawdown 78.75% -16.56% -
Stop losses Take profits
Position Exits
Triggered exits 17 8
Percent winning 0.00% 100.00%
Percent losing 100.00% 0.00%
Percent of total 25.00% 11.76%
Risk Analysis
Biggest realized risk 2.44%
Average realized risk -3.98%
Max pullback of capital -19.36%
Sharpe Ratio 1.33
Sortino Ratio 2.03
Profit Factor 1.25
[13]:
from tradeexecutor.analysis.multipair import analyse_multipair
from tradeexecutor.analysis.multipair import format_multipair_summary

multipair_summary = analyse_multipair(state)
display(format_multipair_summary(multipair_summary))
Trading pair Positions Trades Total PnL USD Best Worst Avg Median Volume Wins Losses Take profits Stop losses Trailing stop losses Volatility Total return %
1 WETH-USDC spot 31 62 4,677.21 4.71% -5.44% 0.29% 1.19% 3,112,457.48 23 23 1 8 0 2.73% 9.03%
0 WETH-USDC short 37 74 23,186.84 4.30% -4.89% -0.79% -1.41% 7,298,158.03 26 26 7 9 0 2.63% -29.38%
[14]:
from tradeexecutor.visual.equity_curve import visualise_returns_over_time

visualise_returns_over_time(returns)
[14]:
../../_images/programming_strategy-examples_long-short-bollingerbands-polygon_27_0.svg
[15]:
from IPython.core.display_functions import display

summary = analysis.calculate_all_summary_stats_by_side(state=state, time_bucket=CANDLE_TIME_BUCKET)

with pd.option_context("display.max_row", None):
    display(summary)
All Long Short
Trading period length 424 days 16 hours - -
Return % 48.43% 9.38% 34.12%
Annualised return % 41.62% 8.06% 29.32%
Cash at start $50,000.00 - -
Value at end $74,213.29 - -
Trade volume $10,410,615.50 $3,112,457.48 $7,298,158.03
Position win percent 72.06% 74.19% 70.27%
Total positions 68 31 37
Won positions 49 23 26
Lost positions 19 8 11
Stop losses triggered 17 8 9
Stop loss % of all 25.00% 25.81% 24.32%
Stop loss % of lost 89.47% 100.00% 81.82%
Winning stop losses 0 0 0
Winning stop losses percent 0.00% 0.00% 0.00%
Losing stop losses 17 8 9
Losing stop losses percent 100.00% 100.00% 100.00%
Take profits triggered 8 1 7
Take profit % of all 11.76% 3.23% 18.92%
Take profit % of won 16.33% 4.35% 26.92%
Zero profit positions 0 0 0
Positions open at the end 0 0 0
Realised profit and loss $27,864.04 $4,677.21 $23,186.84
Unrealised profit and loss $0.00 $0.00 $0.00
Portfolio unrealised value $0.00 $0.00 $0.00
Extra returns on lending pool interest $0.00 $0.00 $0.00
Cash left at the end $74,213.29 - -
Average winning position profit % 2.05% 1.79% 2.29%
Average losing position loss % -3.29% -4.02% -2.76%
Biggest winning position % 4.88% 4.71% 4.88%
Biggest losing position % -5.44% -5.44% -4.31%
Average duration of winning positions 1 days 1 hours 1 days 2 hours 1 days 1 hours
Average duration of losing positions 1 days 10 hours 1 days 7 hours 1 days 12 hours
Average bars of winning positions 6 bars 6 bars 6 bars
Average bars of losing positions 8 bars 7 bars 9 bars
LP fees paid $5,206.61 $1,556.62 $3,649.99
LP fees paid % of volume 0.05% 0.05% 0.05%
Average position 0.56% 0.29% 0.79%
Median position 1.35% 1.19% 1.40%
Most consecutive wins 13 10 5
Most consecutive losses 4 3 2
Biggest realised risk -7.19% -4.35% -7.19%
Avg realised risk -3.98% -3.22% -4.54%
Max pullback of total capital -19.36% - -
Max loss risk at opening of position 2.44% 2.44% -4.88%
Max drawdown -16.56% - -
[16]:
from tradeexecutor.visual.equity_curve import calculate_equity_curve, calculate_returns
from tradeexecutor.analysis.advanced_metrics import visualise_advanced_metrics, AdvancedMetricsMode

equity = calculate_equity_curve(state)
returns = calculate_returns(equity)
metrics = visualise_advanced_metrics(returns, mode=AdvancedMetricsMode.full)

with pd.option_context("display.max_row", None):
    display(metrics)
Strategy
Start Period 2022-07-20
End Period 2023-09-26
Risk-Free Rate 0.0%
Time in Market 22.0%
Cumulative Return 48.43%
CAGR﹪ 39.5%
Sharpe 0.55
Prob. Sharpe Ratio 93.46%
Smart Sharpe 0.51
Sortino 0.86
Smart Sortino 0.8
Sortino/√2 0.61
Smart Sortino/√2 0.57
Omega 1.25
Max Drawdown -16.56%
Longest DD Days 148
Volatility (ann.) 11.26%
Calmar 2.39
Skew 2.76
Kurtosis 72.57
Expected Daily 0.02%
Expected Monthly 2.67%
Expected Yearly 21.83%
Kelly Criterion 9.72%
Risk of Ruin 0.0%
Daily Value-at-Risk -0.95%
Expected Shortfall (cVaR) -0.95%
Max Consecutive Wins 8
Max Consecutive Losses 6
Gain/Pain Ratio 0.42
Gain/Pain (1M) 2.42
Payoff Ratio 1.29
Profit Factor 1.25
Common Sense Ratio 1.92
CPC Index 0.79
Tail Ratio 1.54
Outlier Win Ratio 18.49
Outlier Loss Ratio 2.78
MTD 3.5%
3M 2.23%
6M 0.58%
YTD 14.68%
1Y 53.54%
3Y (ann.) 39.5%
5Y (ann.) 39.5%
10Y (ann.) 39.5%
All-time (ann.) 39.5%
Best Day 10.52%
Worst Day -5.07%
Best Month 14.16%
Worst Month -8.23%
Best Year 29.42%
Worst Year 14.68%
Avg. Drawdown -2.25%
Avg. Drawdown Days 9
Recovery Factor 2.92
Ulcer Index 0.07
Serenity Index 0.35
Avg. Up Month 6.2%
Avg. Down Month -3.89%
Win Days 49.09%
Win Month 66.67%
Win Quarter 60.0%
Win Year 100.0%

Position and trade timeline#

Display all positions and how much profit they made.

[17]:
from tradeexecutor.analysis.trade_analyser import expand_timeline

timeline = analysis.create_timeline()

expanded_timeline, apply_styles = expand_timeline(
        universe.universe.exchanges,
        universe.universe.pairs,
        timeline)

# Do not truncate the row output
with pd.option_context("display.max_row", None):
    display(apply_styles(expanded_timeline))

Remarks Type Opened at Duration Exchange Base asset Quote asset Position max value PnL USD PnL % Open mid price USD Close mid price USD Trade count LP fees
TP Short 2022-07-22 4 hours Uniswap v3 WETH USDC $80,000.00 $3,113.63 4.05% $1,638.329540 $1,574.565143 2 $78.46
SL Long 2022-07-26 13 hours Uniswap v3 WETH USDC $42,428.13 $-1,422.34 -3.35% $1,438.475258 $1,390.252463 2 $41.73
SL Long 2022-08-01 14 hours Uniswap v3 WETH USDC $41,290.26 $-1,599.10 -3.87% $1,669.419998 $1,604.766374 2 $40.50
SL Short 2022-08-05 2 days 21 hours Uniswap v3 WETH USDC $80,021.97 $-2,801.92 -3.39% $1,712.877877 $1,772.823024 2 $81.45
SL Short 2022-08-10 10 hours Uniswap v3 WETH USDC $75,408.94 $-2,764.20 -3.54% $1,838.539276 $1,905.929060 2 $76.81
Short 2022-08-24 4 hours Uniswap v3 WETH USDC $70,863.37 $2,120.92 3.08% $1,663.753808 $1,613.939201 2 $69.82
Short 2022-08-24 1 days 16 hours Uniswap v3 WETH USDC $74,145.08 $1,079.69 1.47% $1,683.333064 $1,658.604414 2 $73.62
SL Long 2022-08-26 8 hours Uniswap v3 WETH USDC $37,877.25 $-2,059.15 -5.44% $1,594.369818 $1,507.693959 2 $36.86
TP Short 2022-08-30 7 hours Uniswap v3 WETH USDC $72,459.86 $2,945.05 4.24% $1,586.259556 $1,521.780208 2 $71.00
TP Short 2022-09-02 3 hours Uniswap v3 WETH USDC $77,058.29 $2,813.77 3.79% $1,636.692111 $1,576.928645 2 $75.67
SL Short 2022-09-06 7 hours Uniswap v3 WETH USDC $81,439.25 $-2,482.09 -2.96% $1,616.200185 $1,665.418311 2 $82.70
TP Short 2022-09-27 13 hours Uniswap v3 WETH USDC $77,335.69 $2,979.28 4.01% $1,385.256802 $1,331.874707 2 $75.87
Long 2022-10-01 1 days 20 hours Uniswap v3 WETH USDC $40,990.51 $156.05 0.38% $1,312.965434 $1,317.963878 2 $41.08
Short 2022-10-04 1 days 8 hours Uniswap v3 WETH USDC $82,230.71 $1,208.06 1.48% $1,349.166317 $1,329.346674 2 $81.65
SL Long 2022-10-07 3 days 5 hours Uniswap v3 WETH USDC $42,016.41 $-1,635.30 -3.89% $1,328.815135 $1,277.097090 2 $41.21
Short 2022-10-14 16 hours Uniswap v3 WETH USDC $81,416.35 $1,906.86 2.39% $1,328.549345 $1,297.434449 2 $80.48
Short 2022-10-17 1 days Uniswap v3 WETH USDC $84,338.44 $1,397.10 1.68% $1,329.080844 $1,307.070592 2 $83.66
SL Short 2022-10-22 1 days 7 hours Uniswap v3 WETH USDC $86,439.84 $-3,149.85 -3.52% $1,316.251723 $1,364.224730 2 $88.04
Long 2022-11-02 1 days 12 hours Uniswap v3 WETH USDC $40,629.73 $1,270.80 3.13% $1,538.303752 $1,586.418182 2 $41.28
Short 2022-11-04 2 days 4 hours Uniswap v3 WETH USDC $83,292.75 $801.44 0.96% $1,624.463446 $1,608.783108 2 $82.92
Long 2022-11-07 12 hours Uniswap v3 WETH USDC $42,221.13 $1,324.93 3.14% $1,551.279275 $1,599.959529 2 $42.89
Long 2022-11-16 3 days 8 hours Uniswap v3 WETH USDC $43,281.07 $838.98 1.94% $1,193.026145 $1,216.152332 2 $43.71
Short 2022-11-24 3 days 20 hours Uniswap v3 WETH USDC $87,904.51 $597.57 0.68% $1,199.605477 $1,191.357101 2 $87.63
Long 2022-11-28 1 days 4 hours Uniswap v3 WETH USDC $44,360.14 $1,236.77 2.79% $1,172.213613 $1,204.895105 2 $44.99
Long 2022-12-04 20 hours Uniswap v3 WETH USDC $45,349.55 $1,310.99 2.89% $1,242.084534 $1,277.991326 2 $46.02
Long 2022-12-07 1 days 8 hours Uniswap v3 WETH USDC $46,398.34 $899.41 1.94% $1,225.797563 $1,249.559006 2 $46.86
Short 2022-12-08 1 days 4 hours Uniswap v3 WETH USDC $94,235.74 $1,614.84 1.74% $1,284.011721 $1,261.990452 2 $93.45
Long 2022-12-12 20 hours Uniswap v3 WETH USDC $48,334.91 $1,169.06 2.42% $1,244.446619 $1,274.545575 2 $48.93
Short 2022-12-20 2 days 8 hours Uniswap v3 WETH USDC $98,540.31 $1,761.93 1.81% $1,207.790181 $1,186.126906 2 $97.69
Short 2022-12-27 16 hours Uniswap v3 WETH USDC $101,202.76 $1,395.83 1.40% $1,227.269267 $1,210.329079 2 $100.53
Long 2022-12-28 3 days 12 hours Uniswap v3 WETH USDC $51,637.58 $165.49 0.32% $1,198.286762 $1,202.127169 2 $51.73
SL Short 2023-01-02 1 days 20 hours Uniswap v3 WETH USDC $103,539.96 $-3,168.63 -2.97% $1,211.903451 $1,248.934414 2 $105.15
Long 2023-01-19 20 hours Uniswap v3 WETH USDC $49,151.18 $1,269.41 2.58% $1,512.828662 $1,551.899802 2 $49.80
TP Short 2023-01-29 14 hours Uniswap v3 WETH USDC $100,333.41 $4,009.81 4.16% $1,653.140314 $1,587.052845 2 $98.35
Short 2023-02-02 3 days 12 hours Uniswap v3 WETH USDC $106,591.54 $1,758.09 1.66% $1,670.588859 $1,642.923061 2 $105.75
Long 2023-02-05 20 hours Uniswap v3 WETH USDC $54,617.34 $842.03 1.54% $1,621.704424 $1,646.705943 2 $55.05
Short 2023-02-08 16 hours Uniswap v3 WETH USDC $110,581.92 $2,251.62 2.08% $1,681.314377 $1,647.035301 2 $109.48
SL Long 2023-02-21 1 days 4 hours Uniswap v3 WETH USDC $57,004.57 $-1,916.50 -3.36% $1,671.424404 $1,615.230804 2 $56.06
Short 2023-03-02 16 hours Uniswap v3 WETH USDC $110,942.74 $2,424.05 2.23% $1,664.086575 $1,627.715462 2 $109.76
Short 2023-03-06 4 hours Uniswap v3 WETH USDC $114,645.43 $867.95 0.76% $1,577.401770 $1,565.459552 2 $114.24
SL Long 2023-03-07 2 days Uniswap v3 WETH USDC $57,925.67 $-2,437.89 -4.21% $1,552.365497 $1,487.031713 2 $56.72
SL Short 2023-03-17 13 hours Uniswap v3 WETH USDC $111,950.72 $-3,583.55 -3.10% $1,764.334287 $1,820.792544 2 $113.77
TP Long 2023-03-22 19 hours Uniswap v3 WETH USDC $53,017.60 $2,495.64 4.71% $1,721.979859 $1,803.036810 2 $54.28
TP Short 2023-03-23 20 hours Uniswap v3 WETH USDC $110,028.22 $5,125.42 4.88% $1,840.378643 $1,754.657568 2 $107.49
Long 2023-03-27 20 hours Uniswap v3 WETH USDC $59,028.28 $1,102.13 1.87% $1,714.077337 $1,746.081204 2 $59.59
Long 2023-04-03 8 hours Uniswap v3 WETH USDC $59,909.99 $917.54 1.53% $1,779.750276 $1,807.007658 2 $60.38
SL Short 2023-04-04 1 days 1 hours Uniswap v3 WETH USDC $121,288.03 $-3,675.44 -2.95% $1,863.526592 $1,920.084537 2 $123.16
Long 2023-04-09 12 hours Uniswap v3 WETH USDC $57,605.25 $573.09 0.99% $1,837.987917 $1,856.273354 2 $57.91
Short 2023-04-10 1 days 8 hours Uniswap v3 WETH USDC $116,127.44 $1,609.20 1.39% $1,890.176101 $1,864.085706 2 $115.36
TP Short 2023-04-26 8 hours Uniswap v3 WETH USDC $118,517.44 $5,148.12 4.54% $1,912.802425 $1,829.735873 2 $115.97
SL Long 2023-05-01 20 hours Uniswap v3 WETH USDC $63,284.41 $-1,974.56 -3.12% $1,871.931031 $1,813.524283 2 $62.31
SL Short 2023-05-04 1 days 17 hours Uniswap v3 WETH USDC $123,409.53 $-5,542.58 -4.31% $1,903.643431 $1,989.269419 2 $126.22
Long 2023-05-17 8 hours Uniswap v3 WETH USDC $57,170.09 $1,131.53 1.98% $1,792.251606 $1,827.724371 2 $57.75
Long 2023-06-26 16 hours Uniswap v3 WETH USDC $58,075.31 $753.98 1.30% $1,856.273447 $1,880.373185 2 $58.47
Long 2023-06-28 16 hours Uniswap v3 WETH USDC $58,678.50 $1,101.57 1.88% $1,833.765613 $1,868.191004 2 $59.24
Short 2023-06-30 4 days Uniswap v3 WETH USDC $119,119.51 $-513.44 -0.47% $1,925.468038 $1,934.151734 2 $119.43
Short 2023-07-10 16 hours Uniswap v3 WETH USDC $118,107.10 $1,878.76 1.61% $1,898.320950 $1,868.191004 2 $117.20
SL Short 2023-07-13 2 hours Uniswap v3 WETH USDC $120,925.49 $-3,769.79 -3.02% $1,927.201653 $1,987.281243 2 $122.84
Long 2023-07-17 1 days 8 hours Uniswap v3 WETH USDC $57,348.64 $680.69 1.19% $1,889.042487 $1,911.463999 2 $57.70
Long 2023-07-31 1 days 8 hours Uniswap v3 WETH USDC $57,893.18 $389.16 0.67% $1,859.059807 $1,871.556607 2 $58.10
Long 2023-08-07 20 hours Uniswap v3 WETH USDC $58,204.52 $590.81 1.02% $1,816.609833 $1,835.049543 2 $58.51
Short 2023-08-08 2 days 12 hours Uniswap v3 WETH USDC $117,354.33 $-42.33 -0.09% $1,841.851462 $1,843.325459 2 $117.44
Short 2023-08-13 4 hours Uniswap v3 WETH USDC $117,098.72 $1,133.59 0.97% $1,856.830292 $1,838.907003 2 $116.56
Long 2023-08-14 8 hours Uniswap v3 WETH USDC $11,709.87 $37.53 0.32% $1,840.746830 $1,846.646266 2 $11.73
SL Long 2023-08-15 1 days 20 hours Uniswap v3 WETH USDC $59,393.00 $-2,919.09 -4.91% $1,827.907235 $1,738.068075 2 $57.95
Long 2023-08-28 16 hours Uniswap v3 WETH USDC $57,057.73 $383.55 0.67% $1,641.117012 $1,652.148777 2 $57.26
Short 2023-09-08 12 hours Uniswap v3 WETH USDC $114,729.13 $1,472.81 1.30% $1,645.718266 $1,624.625893 2 $114.02
Short 2023-09-18 1 days 16 hours Uniswap v3 WETH USDC $116,903.12 $1,265.28 1.08% $1,654.297859 $1,636.528458 2 $116.31

Finishing notes#

Print out a line to signal the notebook finished the execution successfully.

[18]:
print("All ok")
All ok