Unable to make Live Trades on MT5 using an Avellaneda stoikov implementation in Python

 

Hello!

I am relatively new to creating trading algorithms in MQL5 and Python. I am currently using an Avellaneda Stoikov implementation to fetch real time tick data from MT5 and make live trades on it. 

I am using a Metatrader5 Demo account. I have tried changing the paramenters as well but to no avail. Muy code is unable to open any position on metatrader5.

Can you guys please take a look at my code and help me out?

Thanks in advance for any and every help!

import math
import numpy as np
import pandas as pd
import time
import MetaTrader5 as mt5
import pytz
from datetime import datetime, timedelta
from collections import defaultdict

# MetaTrader 5 credentials and login
account = 123456  # Replace with your account number
password = "xyz"  # Replace with your account password
server = "MetaQuotes-Demo"

# Initialize connection to MetaTrader 5
if not mt5.initialize():
    print("initialize() failed")
    mt5.shutdown()
    quit()

# Login to MetaTrader 5
if not mt5.login(login=account, password=password, server=server):
    print("Login failed, error code =", mt5.last_error())
    mt5.shutdown()
    quit()

# Symbol and parameters
symbol = "EURUSD"
lot_size = 0.01  # Minimum lot size for EURUSD
max_positions = 5  # Maximum number of open positions

# Enable trading for the symbol
selected = mt5.symbol_select(symbol, True)
if not selected:
    print(f"Failed to select {symbol}")
    mt5.shutdown()
    quit()

# Set up logging
print("Avellaneda-Stoikov strategy started")

# Avellaneda-Stoikov model parameters
T = 1.0  # Time horizon (1 day)
# sigma = 0.0002  # Volatility (adjust based on EURUSD)
# gamma = 0.1  # Inventory risk aversion
# k = 1.5  # Order book liquidity

sigma = 0.0001  # Volatility (reduced)
gamma = 0.1     # Inventory risk aversion
k = 0.1         # Order book liquidity (increased)

total_trades = 0
profit_loss = 0
trade_history = defaultdict(list)

# Function to get the current price
def get_current_price():
    tick = mt5.symbol_info_tick(symbol)
    return (tick.bid + tick.ask) / 2

# Function to calculate optimal spread
def calculate_optimal_spread(inventory):
    return min((2 / gamma) * math.log(1 + gamma / k), 0.0005)  # Cap the spread at 5 pips

# Function to calculate reservation price
def calculate_reservation_price(mid_price, inventory, time_to_end):
    return mid_price - inventory * gamma * (sigma ** 2) * time_to_end

# Function to place a market order
def place_market_order(action, volume):
    if action == "BUY":
        order_type = mt5.ORDER_TYPE_BUY
    elif action == "SELL":
        order_type = mt5.ORDER_TYPE_SELL
    else:
        return None

    price = mt5.symbol_info_tick(symbol).ask if action == "BUY" else mt5.symbol_info_tick(symbol).bid
    
    request = {
        "action": mt5.TRADE_ACTION_DEAL,
        "symbol": symbol,
        "volume": volume,
        "type": order_type,
        "price": price,
        "deviation": 10,  # Allow some slippage
        "magic": 23400011,
        "comment": f"Avellaneda-Stoikov {action}",
        "type_time": mt5.ORDER_TIME_GTC,
        "type_filling": mt5.ORDER_FILLING_IOC,
    }

    result = mt5.order_send(request)
    if result.retcode != mt5.TRADE_RETCODE_DONE:
        print(f"Order failed, retcode={result.retcode}")
        print(f"Avellaneda-Stoikov: {action} order failed, retcode={result.retcode}")
        return None
    
    print(f"Avellaneda-Stoikov: {action} order placed - Volume: {volume}, Price: {price}")
    return result

# Main trading loop
start_time = datetime.now()
end_time = start_time + timedelta(minutes=3600)  # Run for x minutes
min_spread = 0.00005  # Minimum 1 pip spread

while datetime.now() < end_time:
    # Get current price and time
    current_price = get_current_price()
    current_time = datetime.now()
    time_to_end = (end_time - current_time).total_seconds() / (24*3600)  # Convert to days

    # Get current positions
    positions = mt5.positions_get(symbol=symbol)
    inventory = sum(pos.volume if pos.type == mt5.POSITION_TYPE_BUY else -pos.volume for pos in positions if pos.magic == 23400011)
    current_positions = len([pos for pos in positions if pos.magic == 23400011])


    # Calculate reservation price and optimal spread
    reservation_price = calculate_reservation_price(current_price, inventory, time_to_end)
    optimal_spread = calculate_optimal_spread(inventory)

    # Calculate bid and ask prices
    half_spread = optimal_spread / 2
    bid_price = current_price - half_spread
    ask_price = current_price + half_spread
    # # Calculate reservation price and optimal spread
    # reservation_price = calculate_reservation_price(current_price, inventory, time_to_end)
    # optimal_spread = max(calculate_optimal_spread(inventory), min_spread)

    # # Calculate bid and ask prices
    # bid_price = reservation_price - optimal_spread / 2
    # ask_price = reservation_price + optimal_spread / 2

    # Determine trading action
    print(f"Current price: {current_price:.5f}, Bid: {bid_price:.5f}, Ask: {ask_price:.5f}")
    
    tolerance = 0.00002  # 0.2 pips

    if current_positions < max_positions:
        if current_price <= (bid_price + tolerance):
            print("Attempting to buy...")
            result = place_market_order("BUY", lot_size)
            if result:
                total_trades += 1
                trade_history['BUY'].append(result.price)
        elif current_price >= (ask_price - tolerance):
            print("Attempting to sell...")
            result = place_market_order("SELL", lot_size)
            if result:
                total_trades += 1
                trade_history['SELL'].append(result.price)
        else:
            print("No trading opportunity found")
    else:
        print(f"Maximum positions reached: {current_positions}")

    # Print current status
    print(f"Time: {current_time}, Price: {current_price}, Inventory: {inventory}")
    print(f"Reservation Price: {reservation_price}, Bid: {bid_price}, Ask: {ask_price}")
    print(f"Current positions: {current_positions}, Inventory: {inventory}")
    print(f"Optimal spread: {optimal_spread:.5f}, Min spread: {min_spread:.5f}")
    # Wait for 1 second before next iteration
    time.sleep(1)

print("\n--- Trading Session Results ---")
print(f"Total trades executed: {total_trades}")
print(f"Buy trades: {len(trade_history['BUY'])}")
print(f"Sell trades: {len(trade_history['SELL'])}")

if trade_history['BUY'] and trade_history['SELL']:
    avg_buy_price = sum(trade_history['BUY']) / len(trade_history['BUY'])
    avg_sell_price = sum(trade_history['SELL']) / len(trade_history['SELL'])
    print(f"Average buy price: {avg_buy_price:.5f}")
    print(f"Average sell price: {avg_sell_price:.5f}")


profit_loss = 0
for trade_price in trade_history['BUY']:
    profit_loss -= trade_price * lot_size * 100000  # Buying costs money
for trade_price in trade_history['SELL']:
    profit_loss += trade_price * lot_size * 100000  # Selling earns money

# Add unrealized P&L from open positions
current_price = get_current_price()
for position in mt5.positions_get(symbol=symbol):
    if position.magic == 23400011:  # Only consider positions opened by this strategy
        if position.type == mt5.POSITION_TYPE_BUY:
            profit_loss += (current_price - position.price_open) * position.volume * 100000
        else:
            profit_loss += (position.price_open - current_price) * position.volume * 100000

print(f"Estimated P&L: ${profit_loss:.2f}")

# Log final results to MetaTrader 5
print(f"Avellaneda-Stoikov session ended. Total trades: {total_trades}, Estimated P&L: ${profit_loss:.2f}")

# Shutdown MetaTrader 5 connection
mt5.shutdown()