-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Adds market data producer and types * Adds market l1 ring buffer. Refactors socket/gateway servers * Adds scaffolding for market data server on port 8889 * adds function to send a message to all connected clients * OrderBook sending market data * MarketData server starts on port 8889. Adds libs for ssl and sqlite * Refactors python load test into trading client to ease testing market data * Testing pulling packages from alpine instead of from source * Tries reconfiguring workflow for github * Typo in libspdlog-dev * Trying older catch library * Catch2 / catch packages in ubuntu giving me issues. Rolling back * Transmitting market data * order book tests still failling * Fixes github workflow
- Loading branch information
Showing
19 changed files
with
482 additions
and
233 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,5 +5,6 @@ services: | |
build: . | ||
ports: | ||
- "8888:8888" | ||
- "8889:8889" | ||
volumes: | ||
- ./:/app |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
#!/bin/sh | ||
|
||
cd /app | ||
rm main test | ||
cmake . | ||
make |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Go client is WIP! Use at own peril. Barely documented. |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
import socket | ||
import sys | ||
import time | ||
from struct import pack, unpack | ||
import random | ||
import threading | ||
|
||
|
||
class Client: | ||
port = None | ||
host = None | ||
|
||
def log(self, msg): | ||
print(msg) | ||
|
||
def connect(self): | ||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
self.sock.connect((self.host, self.port)) | ||
response = self.sock.recv(1024) | ||
self.log(response) | ||
|
||
def disconnect(self): | ||
self.sock.close() | ||
|
||
def listener(self): | ||
raise NotImplementedError() | ||
|
||
def start_listener(self): | ||
self.thread = threading.Thread(target=self.listener) | ||
self.thread.start() | ||
|
||
def stop_listener(self): | ||
raise NotImplementedError() | ||
|
||
|
||
class MarketClient(Client): | ||
host = '0.0.0.0' | ||
port = 8889 | ||
|
||
def listener(self): | ||
while True: | ||
data = self.sock.recv(16) | ||
print(data) | ||
print(len(data)) | ||
if not data: | ||
return | ||
|
||
# c is char | ||
# Q is unsigned long long | ||
# i is 4 byte integer | ||
# x is 1 byte padding. | ||
format_string = 'BcxxiQ' | ||
unpacked_data = unpack(format_string, data) | ||
|
||
version = unpacked_data[0] | ||
msg_type = unpacked_data[1].decode() | ||
val = unpacked_data[2] | ||
time_ms = unpacked_data[3] | ||
|
||
self.handle_notification(msg_type, val, time_ms) | ||
|
||
def handle_notification(self, msg_type: str, val: int, time_ms: int): | ||
self.log({'msg_type': msg_type, 'val': val, 'time_ms': time_ms}) | ||
|
||
|
||
class TradingClient(Client): | ||
host = '0.0.0.0' | ||
port = 8888 | ||
|
||
type_to_msg = { | ||
'u': 'updated', | ||
'f': 'filled', | ||
'r': 'recieved' | ||
} | ||
|
||
def __init__(self): | ||
pass | ||
|
||
def trade(self, price: int, quantity: int, side: str): | ||
assert side in ['b', 's'], 'Side must be b or s for buy and sell' | ||
|
||
message = pack( | ||
'cii', | ||
bytes(side, 'ascii'), | ||
price, | ||
quantity, | ||
) | ||
|
||
self.sock.sendall(message) | ||
|
||
def listener(self): | ||
while True: | ||
data = self.sock.recv(21) | ||
if not data: | ||
return | ||
|
||
# c is char | ||
# Q is unsigned long long | ||
# i is 4 byte integer | ||
format_string = 'Qiii' | ||
unpacked_data = unpack(format_string, data[1:]) | ||
msg_type = chr(data[0]) | ||
message = self.type_to_msg[msg_type] | ||
|
||
id = unpacked_data[0] | ||
quantity = unpacked_data[1] | ||
filled_quantity = unpacked_data[2] | ||
client_id = unpacked_data[3] | ||
|
||
self.handle_notification(id, quantity, filled_quantity, client_id) | ||
|
||
def handle_notification(self, id, quantity, filled_quantity, client_id): | ||
self.log({'id': id, 'quantity': quantity, 'filled_quantity': filled_quantity, 'client_id': client_id}) | ||
|
||
|
||
client = TradingClient() | ||
client.connect() | ||
client.start_listener() | ||
|
||
mkt = MarketClient() | ||
mkt.connect() | ||
mkt.start_listener() | ||
|
||
while True: | ||
char = sys.stdin.read(1) | ||
if char == 'b': | ||
break | ||
time.sleep(.1) | ||
print("Placing trade.") | ||
price = random.randint(101, 999) | ||
quantity = random.randint(1, 10) | ||
side = 'b' if random.randint(0, 1) == 0 else 's' | ||
client.trade(price, quantity, side) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
#include "market_data.h" | ||
|
||
MarketData::MarketData(Consumer<L1MarketData>* market_l1_data_consumer) { | ||
this->market_l1_data_consumer = market_l1_data_consumer; | ||
} | ||
|
||
MarketData::~MarketData() throw() {} | ||
|
||
// I don't care about these for now because I am implementing authentication later. | ||
// For now anyone can get market data if they connect. | ||
|
||
void MarketData::newClient(int client_id) { | ||
const char *msg = "Welcome new market data consumer"; | ||
if (!sendMessage(client_id, const_cast<char *>(msg), strlen(msg))) { | ||
forceDisconnect(client_id); | ||
} | ||
} | ||
void MarketData::disconnected(int client_id) {}; | ||
void MarketData::readMessage(int client_id, char *message) {}; | ||
|
||
void MarketData::handleOutgoingMessage() { | ||
L1MarketData *market_data = market_l1_data_consumer->get(); | ||
if (market_data == nullptr) { | ||
return; | ||
} | ||
|
||
// For every client, send market data. | ||
sendMessageToAllClients((char*)market_data, sizeof(L1MarketData)); | ||
SPDLOG_DEBUG("Sent Mkt {} Value {} ", market_data->type, market_data->val); | ||
} | ||
|
||
void MarketData::run() { | ||
bindSocket(8889); | ||
listenToSocket(); | ||
} |
Oops, something went wrong.