View file src/colab/new_grid_trading_btc10.py - Download

# -*- coding: utf-8 -*-
"""new_grid_trading_btc10.ipynb

Automatically generated by Colab.

Original file is located at
    https://colab.research.google.com/drive/1vnopzVzxNOkohlhItSl-1rKtGvKBLZb7

SIMULATION OF BINANCE GRID TRADING

Get the prices here : https://www.binance.com/en/landing/data
and upload them to your Google Drive.
"""

from google.colab import drive
drive.mount('/content/drive')

import numpy as np
from datetime import datetime, timedelta

debut = datetime(2024, 9, 2, 12, 0)
fin = datetime(2024, 9, 13, 23, 0)

def load_hist(filename):
  n = 0
  global price_hist

  f = open('drive/MyDrive/' + filename)
  while (line := f.readline()) != '':
    fields = line.strip().split(',')
    dt = datetime.utcfromtimestamp(int(fields[0])/1000)
    if dt >= debut and dt <= fin:
      high = float(fields[2])
      low = float(fields[3])
      if float(fields[1]) <= float(fields[4]): # up candle
        first = low
        second = high
      else: # down candle
        first = high
        second = low
      price_hist[dt] = first
      price_hist[dt + timedelta(milliseconds=500)] = second
      n = n+1

  f.close()
  print(f"{n} candles loaded")

price_hist = {}

load_hist('BTCUSDT-1s-2024-09-02.csv')
load_hist('BTCUSDT-1s-2024-09-03.csv')
load_hist('BTCUSDT-1s-2024-09-04.csv')
load_hist('BTCUSDT-1s-2024-09-05.csv')
load_hist('BTCUSDT-1s-2024-09-06.csv')
load_hist('BTCUSDT-1s-2024-09-07.csv')
load_hist('BTCUSDT-1s-2024-09-08.csv')
load_hist('BTCUSDT-1s-2024-09-09.csv')
load_hist('BTCUSDT-1s-2024-09-10.csv')
load_hist('BTCUSDT-1s-2024-09-11.csv')
load_hist('BTCUSDT-1s-2024-09-12.csv')
load_hist('BTCUSDT-1s-2024-09-13.csv')

import matplotlib.pyplot as plt

plt.figure(figsize=(15,6))
plt.plot(list(price_hist.keys()), list(price_hist.values()))
plt.show()

import math

def compute_params():

  global price_step
  global llow
  global lhigh
  global lprice_step
  global order_amount
  global fees

  price_step = (high - low) / steps

  llow = math.log(low)
  lhigh = math.log(high)
  lprice_step = (lhigh - llow) / steps

  order_amount = (usdt_amount - reserved) / ((steps * 1.054) + 1.05)
  #order_amount = (usdt_amount - reserved) / (steps + 1)
  fees = order_amount * fees_rate

# Parameters
mode        = "arithmetic" # @param ["arithmetic", "geometric"]
low         = 55738.82  # @param {type:"number"}
high        = 60671.96  # @param {type:"number"}
steps       = 19        # @param {type:"number"}
usdt_amount = 15000     # @param {type:"number"}
stop_loss   = 1         # @param {type:"number"}
take_profit = 64000     # @param {type:"number"}
reserved    = 42.86     # @param {type:"number"}
fees_rate   = 0.001     # @param {type:"number"}

# Calculated values
compute_params()

print(f"Price Step: {price_step:7.2f}")
print(f"Order Amount: {order_amount:7.2f}")
print(f"Fees: {fees:7.4f}")

import math

def level_of_price(price):
  if price < low: return -1
  if price > high: return steps
  if mode == "arithmetic":
    l = math.floor((price - low) / price_step)
  elif mode == "geometric":
    l = math.floor((math.log(price) - llow) / lprice_step)
  return l

level_of_price(61000)

def price_of_level(level):
  if mode == "arithmetic":
    price = low + level * price_step
  elif mode == "geometric":
    price = math.exp(llow + level * lprice_step)
  return price

price_of_level(3)

init_price = list(price_hist.values())[0]
print(init_price)

# Commented out IPython magic to ensure Python compatibility.
# %%script echo Disabled
# 
# # Répartir usdt_amount proportionnellement au nombre de lignes en dessous du cours initial pour usdt et au dessus du cours initial pour crypto
# usdt = usdt_amount * 6 / 20
# crypto = (usdt_amount * 14 / 20) / init_price
# print(f"Start with {usdt} USDT and {crypto} BTC")

for i in range(steps+1):
  print(f"{i:3} {price_of_level(i):9.2f}")

print(list(price_hist.keys())[0])

print(list(price_hist.keys())[-1])

dt1 = list(price_hist.keys())[1000]
print(dt1)

dt_begin = list(price_hist.keys())[0]
dt_end = list(price_hist.keys())[-1]
duration = dt_end - dt_begin
print(duration)
if duration.total_seconds() / 3600 <= 48:
  first_hour = dt_begin.replace(minute=0, second=0, hour=dt_begin.hour+1)
else:
  first_hour = dt_begin.replace(hour=0, minute=0, second=0, day=dt_begin.day+1)
print(first_hour)
print(first_hour + timedelta(hours=1))

def draw_chart():
  plt.figure(figsize=(15,6))
  plt.plot(list(price_hist.keys()), list(price_hist.values()))
  hour = first_hour
  while hour < dt_end:
    plt.axvline(x=hour, color='grey', linestyle='-')
    if duration.total_seconds() / 3600 <= 48:
      hour = hour + timedelta(hours=1)
    else:
      hour = hour + timedelta(days=1)
  for i in range(steps+1):
    plt.axhline(y=price_of_level(i), color='grey', linestyle='-')
  plt.show()

draw_chart()

crypto_hist = {}
usdt_hist = {}
position_hist = {}
achats = []
ventes = []
pairs = []

def trade(price_hist, disp=False):

  #global usdt
  #global crypto

  global crypto_hist
  global usdt_hist
  global position_hist
  global achats
  global ventes
  global pairs

  # Répartir usdt_amount proportionnellement au nombre de lignes en dessous du cours initial pour usdt et au dessus du cours initial pour crypto
  init_price = list(price_hist.values())[0]
  usdt = usdt_amount * (init_price - low) / (high - low)
  crypto = (usdt_amount - usdt) / init_price
  total = usdt + crypto * init_price
  crypto_hist = {}
  usdt_hist = {}
  position_hist = {}

  achats = []
  ventes = []
  pairs = []

  if disp:
    print(f"Initial price: {init_price:9.2f}, USDT: {usdt:9.2f}, crypto: {crypto:9.6f}")

  level = level_of_price(init_price)
  trend = 0
  nt = 0

  for dt, price in price_hist.items():

    if price < stop_loss: break

    if price > take_profit: break

    previous_level = level
    level = level_of_price(price)

    if level < previous_level:
      for i in range(previous_level, level, -1):
        previous_trend = trend
        trend = -1
        if trend == previous_trend or previous_trend == 0:
          nt = nt + 1
          trade_price = price_of_level(i)
          crypto_hist[dt - timedelta(milliseconds=100)] = crypto
          usdt_hist[dt - timedelta(milliseconds=100)] = usdt
          if order_amount != 0:
            # Buy cryptos for order_amount USDT
            tr = [dt, 1, order_amount, order_amount / trade_price, trade_price]
            usdt = usdt - order_amount - fees
            crypto = crypto + order_amount / trade_price
          elif order_amount_crypto != 0:
            # Buy order_amount_crypto
            tr = [dt, 1, order_amount_crypto * trade_price, order_amount_crypto, trade_price]
            crypto = crypto + order_amount_crypto
            usdt = usdt - order_amount_crypto * trade_price - fees
          crypto_hist[dt] = crypto
          usdt_hist[dt] = usdt
          total = usdt + crypto * price
          if len(ventes) == 0:
            achats.append(tr)
          else:
            vente = ventes.pop()
            pairs.append([vente, tr])
          if disp:
            print(f"{dt.strftime('%Y-%m-%d %H:%M:%S')} L{i:3d} ({trade_price:9.2f} ) baisse: {nt:3d} ACHAT -> USDT:{usdt:9.2f}, crypto:{crypto:9.6f}, total:{total:9.2f} gain:{total-usdt_amount:9.2f}")

    elif level > previous_level:
      for i in range(previous_level, level):
        previous_trend = trend
        trend = 1
        if trend == previous_trend or previous_trend == 0:
          nt = nt + 1
          trade_price = price_of_level(i+1)
          crypto_hist[dt - timedelta(milliseconds=100)] = crypto
          usdt_hist[dt - timedelta(milliseconds=100)] = usdt
          if order_amount != 0:
            # Sell cryptos for order_amount USDT
            tr = [dt, -1, order_amount, order_amount / trade_price, trade_price]
            usdt = usdt + order_amount - fees
            crypto = crypto - order_amount / trade_price
          elif order_amount_crypto != 0:
            # Sell order_amount_crypto cryptos
            tr = [dt, -1, order_amount_crypto * trade_price, order_amount_crypto, trade_price]
            crypto = crypto - order_amount_crypto
            usdt = usdt + order_amount_crypto * trade_price - fees
          crypto_hist[dt] = crypto
          usdt_hist[dt] = usdt
          total = usdt + crypto * price
          if len(achats) == 0:
            ventes.append(tr)
          else:
            achat = achats.pop()
            pairs.append([achat, tr])
          if disp:
            print(f"{dt.strftime('%Y-%m-%d %H:%M:%S')} L{i:3d} ({trade_price:9.2f} ) hausse: {nt:3d} VENTE -> USDT:{usdt:9.2f}, crypto:{crypto:9.6f}, total:{total:9.2f} gain:{total-usdt_amount:9.2f}")

    # store position
    # position_hist[dt] = Position(dt, usdt, crypto)

  return total - usdt_amount

def print_trade(tr):
  dt = tr[0].strftime("%d/%m %H:%M")
  direction = tr[1]
  if direction == 1:
    type = "Achat"
  elif direction == -1:
    type = "Vente"
  usdt = tr[2]
  crypto = tr[3]
  trade_price = tr[4]
  print(f"{dt}: {type} price:{trade_price:9.2f} - {usdt:8.2f} USDT ; {crypto:8.6f} crypto")

def print_pair(pair):
  print_trade(pair[0])
  print_trade(pair[1])
  direction0 = pair[0][1]
  direction1 = pair[1][1]
  price = pair[1][4]
  if (direction0 == 1 and direction1 == -1):
    achat_usdt = pair[0][2]
    achat_crypto = pair[0][3]
    achat_price = pair[0][4]
    vente_usdt = pair[1][2]
    vente_crypto = pair[1][3]
    vente_price = pair[1][4]
  elif (direction0 == -1 and direction1 == 1):
    vente_usdt = pair[0][2]
    vente_crypto = pair[0][3]
    vente_price = pair[0][4]
    achat_usdt = pair[1][2]
    achat_crypto = pair[1][3]
    achat_price = pair[1][4]
  benefice = - achat_usdt + vente_usdt * (1 - fees_rate) + (achat_crypto * (1 - fees_rate) - vente_crypto) * price
  print(f"Bénéfice: {benefice:8.2f}")
  print("")

def draw_crypto_hist():
  plt.figure(figsize=(15,6))
  x_values = list(crypto_hist.keys())
  y_values = list(crypto_hist.values())
  plt.plot(x_values, y_values)
  plt.show()

def draw_usdt_hist():
  plt.figure(figsize=(15,6))
  x_values = list(usdt_hist.keys())
  y_values = list(usdt_hist.values())
  plt.plot(x_values, y_values)
  plt.show()

def draw_trajectory(display_datetime=False):
  plt.figure(figsize=(12,9))
  keys = list(crypto_hist.keys())
  x_values = [init_price * x for x in list(crypto_hist.values())]
  y_values = list(usdt_hist.values())
  n = len(x_values)
  u_values = [x_values[i] - y_values[i] for i in range(n)]
  v_values = [x_values[i] + y_values[i] for i in range(n)]
  plt.plot(u_values, v_values)
  if display_datetime:
    for i in range(n//2):
      plt.text(u_values[i*2+1], v_values[i*2+1], keys[i*2+1])
  plt.show()

#steps = 19
#compute_params()
trade(price_hist, True)

draw_crypto_hist()

draw_usdt_hist()

draw_trajectory()

for achat in achats:
  print_trade(achat)

for vente in ventes:
  print_trade(vente)

for pair in pairs:
  print_pair(pair)

# Commented out IPython magic to ensure Python compatibility.
# %%script echo Disabled
# 
# steps = 18
# compute_params()
# trade(price_hist, False)

"""Determinate the optimal number of steps"""

gains = [0 for i in range(0, 30)]

max_gain = 0
max_steps = 0

for steps in range(2, 30):
  compute_params()
  gain = trade(price_hist, False)
  if gain > max_gain:
    max_gain = gain
    max_steps = steps
  gains[steps] = gain
  print(f"{steps:3d} steps: price step:{price_step:8.2f} gain:{gain:8.2f}")

plt.figure(figsize=(15,6))
plt.plot(gains)
plt.show()

steps = max_steps
print(f"{steps} steps")
compute_params()
draw_chart()
trade(price_hist, True)

draw_crypto_hist()

draw_usdt_hist()

draw_trajectory(True)

for pair in pairs:
  print(pair)

for achat in achats:
  print(achat)

for vente in ventes:
  print(vente)

for pair in pairs:
  print_pair(pair)