Momentum Crossover Strategy#
Strategy description#
We use RSI as an indicator of momentum and slow ema and fast ema to indicate trend direction
Buy signal#
The short-term SMA crosses above the long-term SMA. This crossover signals a potential upward trend.
The RSI crosses below 30 and then moves back above it. This suggests that the asset might be moving out of an oversold condition and starting to gain upward momentum.
Sell signal#
The short-term SMA crosses below the long-term SMA. This crossover signals a potential downward trend.
The RSI crosses above 70 and then moves back below it. This suggests that the asset might be moving out of an overbought condition and starting to lose upward momentum.
For both the buy and sell signals, the conditions should be ideally occur around the same time for a stronger signal.
Set up#
Set up the parameters used in in this strategy backtest study.
Backtested blockchain, exchange and trading pair
Backtesting period
Strategy parameters for EMA crossovers
[1]:
import datetime
import pandas as pd
from tradingstrategy.chain import ChainId
from tradingstrategy.timebucket import TimeBucket
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.
# PancakeSwap basic routing supports two way trades with BUSD
# and three way trades with BUSD-BNB hop.
TRADE_ROUTING = TradeRouting.uniswap_v2_usdc
# How often the strategy performs the decide_trades cycle.
# We do it for every 4h.
TRADING_STRATEGY_CYCLE = CycleDuration.cycle_1h
# Strategy keeps its cash in USDC
RESERVE_CURRENCY = ReserveCurrency.usdc
# Time bucket for our candles
CANDLE_TIME_BUCKET = TimeBucket.h1
# Which trading pair we are trading
TRADING_PAIR = (ChainId.ethereum, "uniswap-v2", "WETH", "USDT", 0.0030) # Ether-Tether USD https://tradingstrategy.ai/trading-view/ethereum/uniswap-v2/eth-usdt
# How much of the cash to put on a single trade
POSITION_SIZE = 0.70
#
# Strategy thinking specific parameter
#
BATCH_SIZE = 50
SLOW_EMA_CANDLE_COUNT = 15
FAST_EMA_CANDLE_COUNT = 5
RSI_CANDLE_COUNT = 5
LOOKBACK = 5
RSI_LOWER_THRESHOLD = 30
RSI_UPPER_THRESHOLD = 70
# Range of backtesting and synthetic data generation.
# Because we are using synthetic data actual dates do not really matter -
# only the duration
START_AT = datetime.datetime(2022, 1, 1)
END_AT = datetime.datetime(2023, 4,1)
# Start with 10,000 USD
INITIAL_DEPOSIT = 10_000
# If the price drops 5 we trigger a stop loss
STOP_LOSS_PCT = 0.95
STOP_LOSS_TIME_BUCKET = TimeBucket.h1
Strategy logic and trade decisions#
decide_trades
function decide what trades to take.In this example, we calculate two exponential moving averages (EMAs) and make decisions based on those.
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.overlap import ema
from pandas_ta import rsi
from tradeexecutor.state.visualisation import PlotKind, PlotShape
from tradeexecutor.utils.crossover import contains_cross_over, contains_cross_under
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 tradingstrategy.universe import Universe
from tradeexecutor.strategy.pandas_trader.position_manager import PositionManager
def decide_trades(
timestamp: pd.Timestamp,
universe: Universe,
state: State,
pricing_model: PricingModel,
cycle_debug_data: Dict) -> List[TradeExecution]:
"""The brain function to decide the trades on each trading strategy cycle.
- Reads incoming execution state (positions, past trades)
- Reads the current universe (candles)
- Decides what trades to do next, if any, at current timestamp.
- Outputs strategy thinking for visualisation and debug messages
:param timestamp:
The Pandas timestamp object for this cycle. Matches
TRADING_STRATEGY_CYCLE division.
Always truncated to the zero seconds and minutes, never a real-time clock.
:param universe:
Trading universe that was constructed earlier.
:param state:
The current trade execution state.
Contains current open positions and all previously executed trades, plus output
for statistics, visualisation and diangnostics of the strategy.
:param pricing_model:
Pricing model can tell the buy/sell price of the particular asset at a particular moment.
:param cycle_debug_data:
Python dictionary for various debug variables you can read or set, specific to this trade cycle.
This data is discarded at the end of the trade cycle.
:return:
List of trade instructions in the form of :py:class:`TradeExecution` instances.
The trades can be generated using `position_manager` but strategy could also hand craft its trades.
"""
# The pair we are trading
pair = universe.pairs.get_single()
# How much cash we have in the 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=BATCH_SIZE)
# 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 averages based on slow and fast sample numbers.
slow_ema_series = ema(close_prices, length=SLOW_EMA_CANDLE_COUNT)
fast_ema_series = ema(close_prices, length=FAST_EMA_CANDLE_COUNT)
rsi_series = rsi(close_prices, length=RSI_CANDLE_COUNT)
slow_ema_latest = slow_ema_series.iloc[-1]
fast_ema_latest = fast_ema_series.iloc[-1]
price_latest = close_prices.iloc[-1]
rsi_latest = rsi_series.iloc[-1]
trades = []
# Create a position manager helper class that allows us easily to create
# opening/closing trades for different positions
position_manager = PositionManager(timestamp, universe, state, pricing_model)
if not position_manager.is_any_open():
# No open positions, decide if BUY in this cycle.
# Buy Signal:
#
# 1. The short-term SMA crosses above the long-term SMA. This crossover signals a potential upward trend.
# 2. The RSI crosses below 30 and then moves back above it. This suggests that the asset might be moving out of an oversold condition and starting to gain upward momentum.
#
# Both conditions should occur around the same time for a stronger buy signal.
crossover_ema, ema_crossover_index = contains_cross_over(
fast_ema_series,
slow_ema_series,
lookback_period=LOOKBACK,
must_return_index=True
)
crossunder_rsi_30, rsi_crossunder_index = contains_cross_under(
rsi_series,
pd.Series([RSI_LOWER_THRESHOLD] * len(rsi_series)),
lookback_period=LOOKBACK,
must_return_index=True
)
crossover_rsi_30, rsi_crossover_index = contains_cross_over(
rsi_series,
pd.Series([RSI_LOWER_THRESHOLD] * len(rsi_series)),
lookback_period=LOOKBACK,
must_return_index=True
)
if (crossover_ema and crossunder_rsi_30 and crossover_rsi_30) \
and (ema_crossover_index == -1 or rsi_crossover_index == -1) \
and rsi_crossunder_index < rsi_crossover_index:
# Buy condition is met
buy_amount = cash * POSITION_SIZE
new_trades = position_manager.open_1x_long(
pair,
buy_amount,
stop_loss_pct=STOP_LOSS_PCT
)
trades.extend(new_trades)
assert len(new_trades) == 1
else:
# Sell Signal:
#
# 1. The short-term SMA crosses below the long-term SMA. This crossover signals a potential downward trend.
# 2. The RSI crosses above 70 and then moves back below it. This suggests that the asset might be moving out of an overbought condition and starting to lose upward momentum.
# Again, for a stronger sell signal, both conditions should ideally occur around the same time.
crossunder_ema, ema_crossunder_index = contains_cross_under(
fast_ema_series,
slow_ema_series,
lookback_period=LOOKBACK,
must_return_index=True
)
crossunder_rsi_70, rsi_crossunder_index = contains_cross_under(
rsi_series,
pd.Series([RSI_UPPER_THRESHOLD] * len(rsi_series)),
lookback_period=LOOKBACK,
must_return_index=True
)
crossover_rsi_70, rsi_crossover_index = contains_cross_over(
rsi_series,
pd.Series([RSI_UPPER_THRESHOLD] * len(rsi_series)),
lookback_period=LOOKBACK,
must_return_index=True
)
if (crossunder_ema and crossover_rsi_70 and crossunder_rsi_70) \
and (ema_crossunder_index == -1 or rsi_crossover_index == -1) \
and rsi_crossover_index < rsi_crossunder_index:
# sell condition is met
new_trades = position_manager.close_all()
assert len(new_trades) == 1
trades.extend(new_trades)
# Visualize strategy
# See available Plotly colours here
# https://community.plotly.com/t/plotly-colours-list/11730/3?u=miohtama
visualisation = state.visualisation
visualisation.plot_indicator(timestamp, "Fast EMA", PlotKind.technical_indicator_on_price, fast_ema_latest, colour="red")
visualisation.plot_indicator(timestamp, "Slow EMA", PlotKind.technical_indicator_on_price, slow_ema_latest, colour="green")
visualisation.plot_indicator(timestamp, "RSI", PlotKind.technical_indicator_detached, rsi_latest, colour="orange")
visualisation.plot_indicator(timestamp, "RSI 30", PlotKind.technical_indicator_overlay_on_detached, RSI_LOWER_THRESHOLD, colour="green", detached_overlay_name="RSI")
visualisation.plot_indicator(timestamp, "RSI 70", PlotKind.technical_indicator_overlay_on_detached, RSI_UPPER_THRESHOLD, colour="green", detached_overlay_name="RSI")
return trades
Defining the trading universe#
We create a trading universe with a single blockchain, exchange and trading pair. For the sake of easier understanding the code, we name this “Uniswap v2” like exchange with a single ETH-USDC trading pair.
The trading pair contains generated noise-like OHLCV trading data.
[3]:
from typing import Optional
from tradeexecutor.strategy.trading_strategy_universe import load_pair_data_for_single_exchange, TradingStrategyUniverse
from tradeexecutor.strategy.execution_context import ExecutionContext
from tradeexecutor.strategy.universe_model import UniverseOptions
from tradingstrategy.client import Client
import datetime
def create_single_pair_trading_universe(
ts: datetime.datetime,
client: Client,
execution_context: ExecutionContext,
universe_options: UniverseOptions,
) -> TradingStrategyUniverse:
dataset = load_pair_data_for_single_exchange(
client,
execution_context,
CANDLE_TIME_BUCKET,
pair_tickers=[TRADING_PAIR],
universe_options=universe_options,
stop_loss_time_bucket=STOP_LOSS_TIME_BUCKET
)
# Filter down to the single pair we are interested in
universe = TradingStrategyUniverse.create_single_pair_universe(
dataset,
pair=TRADING_PAIR,
)
return 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 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()
)
print(f"We loaded {universe.universe.candles.get_candle_count():,} candles.")
We loaded 29,212 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]:
import logging
from tradeexecutor.backtest.backtest_runner import run_backtest_inline
state, universe, debug_dump = run_backtest_inline(
name="ETH/USDC fast and slow EMA example",
start_at=START_AT,
end_at=END_AT,
client=client,
cycle_duration=TRADING_STRATEGY_CYCLE,
decide_trades=decide_trades,
universe=universe,
# create_trading_universe=create_single_pair_trading_universe,
initial_deposit=INITIAL_DEPOSIT,
reserve_currency=RESERVE_CURRENCY,
trade_routing=TRADE_ROUTING,
log_level=logging.WARNING,
)
trade_count = len(list(state.portfolio.get_all_trades()))
print(f"Backtesting completed, backtested strategy made {trade_count} trades")
Backtesting completed, backtested strategy made 70 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: 35
Trades made: 70
[8]:
from tradeexecutor.visual.single_pair import visualise_single_pair
figure = visualise_single_pair(
state,
universe.universe.candles,
start_at=START_AT,
end_at=END_AT,
height = 1000,
)
figure.show()
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
[9]:
from tradeexecutor.visual.benchmark import visualise_benchmark
traded_pair = universe.universe.pairs.get_single()
fig = visualise_benchmark(
state.name,
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=800
)
fig.show()
Equity curve and drawdown#
Visualise equity curve and related performnace over time:
Returns
Drawdown
Daily return
[10]:
# Set Jupyter Notebook output mode parameters
# Used to avoid warnings
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)
[10]:
Returns monthly breakdown#
Monthly returns
Best day/week/month/year
[11]:
from tradeexecutor.visual.equity_curve import visualise_returns_over_time
visualise_returns_over_time(returns)
[11]:
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
[12]:
from tradeexecutor.analysis.trade_analyser import build_trade_analysis
analysis = build_trade_analysis(state.portfolio)
Strategy summary#
Overview of strategy performance
[13]:
from IPython.core.display_functions import display
summary = analysis.calculate_summary_statistics(CANDLE_TIME_BUCKET, state)
with pd.option_context("display.max_row", None):
summary.display()
Returns | |
---|---|
Annualised return % | -32.95% |
Lifetime return % | -38.95% |
Realised PnL | $-3,895.37 |
Trade period | 431 days 13 hours |
Holdings | |
---|---|
Total assets | $6,104.63 |
Cash left | $6,104.63 |
Open position value | $0.00 |
Open positions | 0 |
Winning | Losing | Total | |
---|---|---|---|
Closed Positions | |||
Number of positions | 9 | 26 | 35 |
% of total | 25.71% | 74.29% | 100.00% |
Average PnL % | 8.48% | -5.36% | -1.80% |
Median PnL % | 4.51% | -5.87% | -5.63% |
Biggest PnL % | 29.17% | -9.84% | - |
Average duration | 156 bars | 63 bars | 87 bars |
Max consecutive streak | 2 | 9 | - |
Max runup / drawdown | 26.43% | -46.34% | - |
Stop losses | Take profits | |
---|---|---|
Position Exits | ||
Triggered exits | 18 | 0 |
Percent winning | 0.00% | - |
Percent losing | 100.00% | - |
Percent of total | 51.43% | 0.00% |
Risk Analysis | |
---|---|
Biggest realized risk | 3.70% |
Average realized risk | -3.75% |
Max pullback of capital | -42.96% |
Sharpe Ratio | -154.57% |
Sortino Ratio | -202.40% |
Profit Factor | 90.72% |
Performance metrics#
Here is an example how to use Quantstats library to calculate the tearsheet metrics for the strategy with advanced metrics. The metrics include popular risk-adjusted return comparison metrics.
This includes metrics like:
Sharpe
Sortino
Max drawdown
Note: These metrics are based on equity curve and returns. Analysis here does not go down to the level of an individual trade or a position. Any consecutive wins and losses are measured in days, not in trade or candle counts.
[14]:
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-01-01 |
End Period | 2023-03-31 |
Risk-Free Rate | 0.0% |
Time in Market | 29.0% |
Cumulative Return | -38.95% |
CAGR﹪ | -32.75% |
Sharpe | -0.32 |
Prob. Sharpe Ratio | 4.05% |
Smart Sharpe | -0.3 |
Sortino | -0.42 |
Smart Sortino | -0.4 |
Sortino/√2 | -0.3 |
Smart Sortino/√2 | -0.29 |
Omega | 0.91 |
Max Drawdown | -46.34% |
Longest DD Days | 367 |
Volatility (ann.) | 4.85% |
Calmar | -0.71 |
Skew | -1.45 |
Kurtosis | 39.45 |
Expected Daily | -0.0% |
Expected Monthly | -3.24% |
Expected Yearly | -21.87% |
Kelly Criterion | -5.1% |
Risk of Ruin | 0.0% |
Daily Value-at-Risk | -0.42% |
Expected Shortfall (cVaR) | -0.42% |
Max Consecutive Wins | 10 |
Max Consecutive Losses | 8 |
Gain/Pain Ratio | -0.32 |
Gain/Pain (1M) | -0.7 |
Payoff Ratio | 0.91 |
Profit Factor | 0.91 |
Common Sense Ratio | 0.84 |
CPC Index | 0.41 |
Tail Ratio | 0.92 |
Outlier Win Ratio | 17.25 |
Outlier Loss Ratio | 2.84 |
MTD | -11.37% |
3M | -10.25% |
6M | -17.83% |
YTD | -9.83% |
1Y | -45.24% |
3Y (ann.) | -32.75% |
5Y (ann.) | -32.75% |
10Y (ann.) | -32.75% |
All-time (ann.) | -32.75% |
Best Day | 3.11% |
Worst Day | -4.16% |
Best Month | 10.24% |
Worst Month | -15.51% |
Best Year | -9.83% |
Worst Year | -32.3% |
Avg. Drawdown | -4.31% |
Avg. Drawdown Days | 22 |
Recovery Factor | -0.84 |
Ulcer Index | 0.31 |
Serenity Index | -0.01 |
Avg. Up Month | 3.55% |
Avg. Down Month | -6.3% |
Win Days | 49.84% |
Win Month | 33.33% |
Win Quarter | 20.0% |
Win Year | 0.0% |
Position and trade timeline#
Display all positions and how much profit they made.
[15]:
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 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Long | 2022-01-02 | 3 days 5 hours | Uniswap v2 | WETH | USDT | $7,000.00 | $9.57 | 0.14% | $3,765.178580 | $3,770.327724 | 2 | $42.09 | |
SL | Long | 2022-01-15 | 2 days 7 hours | Uniswap v2 | WETH | USDT | $7,006.70 | $-408.28 | -5.83% | $3,351.829545 | $3,156.519572 | 2 | $40.87 |
Long | 2022-01-28 | 2 days 21 hours | Uniswap v2 | WETH | USDT | $6,720.91 | $224.85 | 3.35% | $2,443.682125 | $2,525.436060 | 2 | $41.06 | |
Long | 2022-02-03 | 5 days 4 hours | Uniswap v2 | WETH | USDT | $6,878.30 | $1,051.78 | 15.29% | $2,657.784407 | $3,064.192881 | 2 | $44.50 | |
SL | Long | 2022-02-10 | 8 hours | Uniswap v2 | WETH | USDT | $7,614.55 | $-490.63 | -6.44% | $3,232.337368 | $3,024.067458 | 2 | $44.28 |
Long | 2022-02-12 | 3 hours | Uniswap v2 | WETH | USDT | $7,271.10 | $-273.49 | -3.76% | $2,978.182736 | $2,866.162998 | 2 | $42.87 | |
SL | Long | 2022-03-02 | 1 days 1 hours | Uniswap v2 | WETH | USDT | $7,079.66 | $-474.36 | -6.70% | $3,023.024471 | $2,820.473643 | 2 | $41.11 |
SL | Long | 2022-03-10 | 6 hours | Uniswap v2 | WETH | USDT | $6,747.61 | $-380.88 | -5.64% | $2,735.237238 | $2,580.842854 | 2 | $39.40 |
Long | 2022-03-13 | 18 days 12 hours | Uniswap v2 | WETH | USDT | $6,481.00 | $1,890.42 | 29.17% | $2,605.750649 | $3,365.813858 | 2 | $44.63 | |
SL | Long | 2022-04-08 | 2 days 19 hours | Uniswap v2 | WETH | USDT | $7,804.29 | $-512.33 | -6.56% | $3,301.176679 | $3,084.463039 | 2 | $45.35 |
SL | Long | 2022-04-13 | 4 days 15 hours | Uniswap v2 | WETH | USDT | $7,445.66 | $-433.59 | -5.82% | $3,084.875541 | $2,905.230194 | 2 | $43.44 |
SL | Long | 2022-04-24 | 12 hours | Uniswap v2 | WETH | USDT | $7,142.14 | $-402.32 | -5.63% | $2,966.218777 | $2,799.131884 | 2 | $41.71 |
SL | Long | 2022-04-28 | 2 days 7 hours | Uniswap v2 | WETH | USDT | $6,860.52 | $-514.97 | -7.51% | $2,938.836483 | $2,718.240650 | 2 | $39.68 |
SL | Long | 2022-05-02 | 3 days 14 hours | Uniswap v2 | WETH | USDT | $6,500.05 | $-372.29 | -5.73% | $2,845.392867 | $2,682.421191 | 2 | $37.94 |
SL | Long | 2022-05-22 | 4 days 7 hours | Uniswap v2 | WETH | USDT | $6,239.44 | $-498.10 | -7.98% | $1,983.925829 | $1,825.548143 | 2 | $35.99 |
Long | 2022-05-31 | 23 hours | Uniswap v2 | WETH | USDT | $5,890.77 | $-255.34 | -4.33% | $1,996.179749 | $1,909.655153 | 2 | $34.63 | |
SL | Long | 2022-06-12 | 8 hours | Uniswap v2 | WETH | USDT | $5,712.04 | $-360.69 | -6.31% | $1,528.325761 | $1,431.817518 | 2 | $33.24 |
Long | 2022-06-27 | 12 hours | Uniswap v2 | WETH | USDT | $5,459.55 | $-0.69 | -0.01% | $1,211.573827 | $1,211.421532 | 2 | $32.80 | |
Long | 2022-07-01 | 8 days | Uniswap v2 | WETH | USDT | $5,459.07 | $697.43 | 12.78% | $1,075.426103 | $1,212.819042 | 2 | $34.90 | |
SL | Long | 2022-07-20 | 1 days 3 hours | Uniswap v2 | WETH | USDT | $5,947.27 | $-351.23 | -5.91% | $1,563.595945 | $1,471.253346 | 2 | $34.68 |
SL | Long | 2022-07-30 | 2 days 4 hours | Uniswap v2 | WETH | USDT | $5,701.41 | $-362.02 | -6.35% | $1,733.418730 | $1,623.351409 | 2 | $33.17 |
SL | Long | 2022-08-23 | 3 days 15 hours | Uniswap v2 | WETH | USDT | $5,447.99 | $-396.94 | -7.29% | $1,620.089743 | $1,502.049074 | 2 | $31.54 |
Long | 2022-09-04 | 9 days 2 hours | Uniswap v2 | WETH | USDT | $5,170.13 | $233.02 | 4.51% | $1,559.670251 | $1,629.966678 | 2 | $31.77 | |
Long | 2022-09-20 | 2 hours | Uniswap v2 | WETH | USDT | $5,333.25 | $-184.05 | -3.45% | $1,380.246836 | $1,332.613364 | 2 | $31.49 | |
SL | Long | 2022-09-26 | 17 days 2 hours | Uniswap v2 | WETH | USDT | $5,204.41 | $-337.90 | -6.49% | $1,323.147575 | $1,237.241994 | 2 | $30.26 |
Long | 2022-10-18 | 2 days 5 hours | Uniswap v2 | WETH | USDT | $4,967.88 | $-203.91 | -4.10% | $1,338.499817 | $1,283.559649 | 2 | $29.24 | |
Long | 2022-10-27 | 2 days 21 hours | Uniswap v2 | WETH | USDT | $4,825.15 | $61.30 | 1.27% | $1,571.731172 | $1,591.698428 | 2 | $29.18 | |
Long | 2022-11-06 | 2 hours | Uniswap v2 | WETH | USDT | $4,868.05 | $-75.54 | -1.55% | $1,636.359566 | $1,610.966039 | 2 | $29.02 | |
Long | 2022-12-22 | 12 days 6 hours | Uniswap v2 | WETH | USDT | $4,815.17 | $-43.72 | -0.91% | $1,218.197728 | $1,207.137421 | 2 | $28.80 | |
Long | 2023-01-17 | 1 days 11 hours | Uniswap v2 | WETH | USDT | $4,784.57 | $-95.94 | -2.01% | $1,575.366495 | $1,543.777728 | 2 | $28.46 | |
Long | 2023-02-01 | 1 days 2 hours | Uniswap v2 | WETH | USDT | $4,717.41 | $28.94 | 0.61% | $1,627.482886 | $1,637.465579 | 2 | $28.43 | |
Long | 2023-02-11 | 7 days 20 hours | Uniswap v2 | WETH | USDT | $4,737.67 | $434.64 | 9.17% | $1,536.770426 | $1,677.754644 | 2 | $29.78 | |
SL | Long | 2023-02-23 | 2 days 6 hours | Uniswap v2 | WETH | USDT | $5,041.91 | $-314.98 | -6.25% | $1,665.967947 | $1,561.892238 | 2 | $29.35 |
SL | Long | 2023-03-01 | 1 days 4 hours | Uniswap v2 | WETH | USDT | $4,821.43 | $-331.47 | -6.87% | $1,660.432439 | $1,546.279217 | 2 | $27.97 |
SL | Long | 2023-03-08 | 1 days 4 hours | Uniswap v2 | WETH | USDT | $4,589.40 | $-451.66 | -9.84% | $1,565.774140 | $1,411.682029 | 2 | $26.22 |
Finishing notes#
Print out a line to signal the notebook finished the execution successfully.
[16]:
print("All ok")
All ok