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