Skip to content

Client Management Bot Example

This example demonstrates how to create a bot that manages client accounts. The bot has a simple strategy:

  • Every three seconds, it will hit a random price in the electronic broker.
  • Every five seconds, it will add a random order in the electronic broker.
  • For each client call that needs a quotation, it will quote a price that has a random spread between 1 and 10 from the market price.
  • For each client call that has a price, it will accept the call only if it can make an arbitrage.

Bot Implementation

```python import random import time import sys import traceback from traderion.bot import TraderionBot from traderion.dashboard import Dashboard, format_number import curses

Direction constants

BID, ASK = (0, 1)

class ClientsManagerBot(TraderionBot): """ The bot will have a simple strategy:

Every three seconds it will hit a random price in the electronic broker.
Every five seconds it will add a random order in the electronic broker.
For each client call that needs a quotation, it will quote a price that has a random spread between 1 and 10 from the market price.
For each client call that has a price, it will accept the call only if it can make an arbitrage.
"""

def __init__(self, username, password, room_id, loop_sleep=1, dashboard=None):
    super().__init__(username, password, room_id, loop_sleep)
    # The timer will count how many times the loop is called
    self.timer = 0

    # Dashboard integration
    self.dashboard = dashboard

    self.clients_data = {
        'accepted_mm_calls': 0,
        'total_mm_calls': 0,
        'accepted_mt_calls': 0,
        'total_mt_calls': 0,
        'last_client_call': 'None',
        'last_deal_amount': 0.0000,
        'last_deal_price': 0.0000
    }
    if self.dashboard:
        self.dashboard.update_core_data('status', 'Connecting')
        self.dashboard.add_custom_panel(self.get_dashboard_panel())
        self.dashboard.update_core_data('position', {'amount': 0, 'pnl': 0, 'rate': 0})
        self.dashboard.update_core_data('market_prices', {'bid': 0.0000, 'ask': 0.0000, 'open': 0.0000})

def get_dashboard_panel(self):
    def clients_panel(stdscr, y, x, height, width):
        stdscr.addstr(y, x, "Clients Strategy", curses.A_BOLD)
        stdscr.addstr(y + 1, x + 2, f"MM Calls: {self.clients_data.get('accepted_mm_calls', 0)}/{self.clients_data.get('total_mm_calls', 0)}")
        stdscr.addstr(y + 2, x + 2, f"MT Calls: {self.clients_data.get('accepted_mt_calls', 0)}/{self.clients_data.get('total_mt_calls', 0)}")
        stdscr.addstr(y + 3, x + 2, f"Last Client: {self.clients_data.get('last_client_call', 'N/A')}")
        stdscr.addstr(y + 4, x + 2, f"Last Deal Amt: {format_number(self.clients_data.get('last_deal_amount', 0))}")
        stdscr.addstr(y + 5, x + 2, f"Last Deal Prc: {format_number(self.clients_data.get('last_deal_price', 0))}")
    return clients_panel

def on_market_price_change(self, old_prices, new_prices):
    """
    Callback for market price changes.
    """
    if self.dashboard:
        self.dashboard.update_core_data('market_prices', new_prices)
        self.dashboard.add_market_event('Market Price Change', f"From {old_prices} to {new_prices}")

def on_price_curve_change(self, old_price_curve, new_price_curve):
    """
    Callback for price curve changes.
    """
    if self.dashboard:
        self.dashboard.add_market_event('Price Curve Change', "Price curve updated")

def on_new_client_call(self, client_call):
    """
    Callback for new client calls.
    """
    if self.dashboard:
        self.dashboard.add_bot_event('New Client Call', f"Direction: {'BID' if client_call['direction'] == BID else 'ASK'}")
        self.clients_data['last_client_call'] = f"Direction: {'BID' if client_call['direction'] == BID else 'ASK'}"

    if client_call['client_price'] is not None:
        # The client had already set the price, we have to either accept or decline
        self.check_for_arbitrage(client_call)
    else:
        # We need to quote to the client
        self.quote_to_client_call(client_call)

def on_client_deal(self, client_call):
    """
    Callback for client deals.
    """
    if self.dashboard:
        self.dashboard.add_bot_event('Client Deal', f"Direction: {'BID' if client_call['direction'] == BID else 'ASK'}")
        self.clients_data['accepted_mm_calls'] += 1
        self.clients_data['total_mm_calls'] += 1
        self.clients_data['last_client_call'] = f"Deal: {'BID' if client_call['direction'] == BID else 'ASK'}"
        self.clients_data['last_deal_amount'] = client_call.get('amount', 0.0000)
        self.clients_data['last_deal_price'] = client_call.get('client_price', 0.0000)

def on_client_reject(self, client_call):
    """
    Callback for client rejections.
    """
    if self.dashboard:
        self.dashboard.add_bot_event('Client Reject', f"Direction: {'BID' if client_call['direction'] == BID else 'ASK'}")
        self.clients_data['total_mm_calls'] += 1
        self.clients_data['last_client_call'] = f"Reject: {'BID' if client_call['direction'] == BID else 'ASK'}"

def on_eb_depth_change(self, old_depth, new_depth):
    """
    Callback for electronic broker depth changes.
    """
    if self.dashboard:
        self.dashboard.add_market_event('EB Depth Change', "Depth updated")

def on_orders_change(self, old_orders, new_orders):
    """
    Callback for orders changes.
    """
    if self.dashboard:
        self.dashboard.add_bot_event('Orders Change', f"{len(new_orders)} active orders")

def on_position_change(self, old_position, new_position):
    """
    Callback for position changes.
    """
    if self.dashboard:
        self.dashboard.update_core_data('position', {
            'amount': new_position['amount'],
            'pnl': new_position['pnl'],
            'rate': new_position['rate']
        })
        self.dashboard.add_performance_metric('Position Change', new_position['pnl'])

def on_room_status_change(self, old_status, new_status):
    """ Callback for room status updates """
    if self.dashboard:
        status_text = new_status
        self.dashboard.update_core_data('status', status_text)
        if old_status != status_text:
            self.dashboard.add_bot_event('Room Status Change', f"From {old_status} to {status_text}")

def main_loop(self):
    """
    Main loop of the bot.
    """
    self.timer += self.loop_sleep

    # Update position
    position = self.api.get_position()
    if self.dashboard:
        self.dashboard.update_core_data('position', {
            'amount': position['amount'],
            'pnl': position['pnl'],
            'rate': position.get('rate', 0)
        })

    # Perform actions based on the timer
    if self.timer % 3 == 0:
        self.random_hit_eb()

    if self.timer % 5 == 0:
        self.random_add_eb()

def get_random_amount(self):
    """
    Returns a random short amount between the min_ticket and the max_ticket.
    """
    room_params = self.api.get_room_parameters()
    min_ticket = room_params['min_ticket']
    max_ticket = room_params['max_ticket']
    return random.randint(min_ticket, max_ticket)

def get_random_direction(self):
    """
    Returns a random direction (BID or ASK).
    """
    return random.choice([BID, ASK])

def get_random_spread(self):
    """
    Returns a random spread between 1 and 10 points.
    """
    return random.randint(1, 10)

def compute_price_from_spread(self, anchor_price, spread, direction):
    """
    Computes a price from the given anchor price, spread, and direction.
    """
    room_params = self.api.get_room_parameters()
    # Compute the value of a pip (FX), cent (EQ), basis point (FI).
    point = 10 ** -(room_params['price_decimals'])
    sgn = (-1, 1)[direction == BID]
    return anchor_price - sgn * spread * point

def random_hit_eb(self):
    """
    Hits a random price in