Add Initial commit
This commit is contained in:
File diff suppressed because it is too large
Load Diff
1021772
CM2005 Object Oriented Programming/Midterm/Merkelrex-TradingBot/20200601.csv
Normal file
1021772
CM2005 Object Oriented Programming/Midterm/Merkelrex-TradingBot/20200601.csv
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,105 @@
|
||||
#include "CSVReader.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
|
||||
CSVReader::CSVReader()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::vector<OrderBookEntry> CSVReader::readCSV(std::string csvFilename)
|
||||
{
|
||||
std::vector<OrderBookEntry> entries;
|
||||
|
||||
std::ifstream csvFile{csvFilename};
|
||||
std::string line;
|
||||
if (csvFile.is_open())
|
||||
{
|
||||
while(std::getline(csvFile, line))
|
||||
{
|
||||
try {
|
||||
OrderBookEntry obe = stringsToOBE(tokenise(line, ','));
|
||||
entries.push_back(obe);
|
||||
}catch(const std::exception& e)
|
||||
{
|
||||
std::cout << "CSVReader::readCSV bad data" << std::endl;
|
||||
}
|
||||
}// end of while
|
||||
}
|
||||
|
||||
std::cout << "CSVReader::readCSV read " << entries.size() << " entries" << std::endl;
|
||||
return entries;
|
||||
}
|
||||
|
||||
std::vector<std::string> CSVReader::tokenise(std::string csvLine, char separator)
|
||||
{
|
||||
std::vector<std::string> tokens;
|
||||
signed int start, end;
|
||||
std::string token;
|
||||
start = csvLine.find_first_not_of(separator, 0);
|
||||
do{
|
||||
end = csvLine.find_first_of(separator, start);
|
||||
if (start == csvLine.length() || start == end) break;
|
||||
if (end >= 0) token = csvLine.substr(start, end - start);
|
||||
else token = csvLine.substr(start, csvLine.length() - start);
|
||||
tokens.push_back(token);
|
||||
start = end + 1;
|
||||
}while(end > 0);
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
OrderBookEntry CSVReader::stringsToOBE(std::vector<std::string> tokens)
|
||||
{
|
||||
double price, amount;
|
||||
|
||||
if (tokens.size() != 5) // bad
|
||||
{
|
||||
std::cout << "Bad line " << std::endl;
|
||||
throw std::exception{};
|
||||
}
|
||||
// we have 5 tokens
|
||||
try {
|
||||
price = std::stod(tokens[3]);
|
||||
amount = std::stod(tokens[4]);
|
||||
}catch(const std::exception& e){
|
||||
std::cout << "CSVReader::stringsToOBE Bad float! " << tokens[3]<< std::endl;
|
||||
std::cout << "CSVReader::stringsToOBE Bad float! " << tokens[4]<< std::endl;
|
||||
throw;
|
||||
}
|
||||
|
||||
OrderBookEntry obe{price,
|
||||
amount,
|
||||
tokens[0],
|
||||
tokens[1],
|
||||
OrderBookEntry::stringToOrderBookType(tokens[2])};
|
||||
|
||||
return obe;
|
||||
}
|
||||
|
||||
|
||||
OrderBookEntry CSVReader::stringsToOBE(std::string priceString,
|
||||
std::string amountString,
|
||||
std::string timestamp,
|
||||
std::string product,
|
||||
OrderBookType orderType)
|
||||
{
|
||||
double price, amount;
|
||||
try {
|
||||
price = std::stod(priceString);
|
||||
amount = std::stod(amountString);
|
||||
}catch(const std::exception& e){
|
||||
std::cout << "CSVReader::stringsToOBE Bad float! " << priceString<< std::endl;
|
||||
std::cout << "CSVReader::stringsToOBE Bad float! " << amountString<< std::endl;
|
||||
throw;
|
||||
}
|
||||
OrderBookEntry obe{price,
|
||||
amount,
|
||||
timestamp,
|
||||
product,
|
||||
orderType};
|
||||
|
||||
return obe;
|
||||
}
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "OrderBookEntry.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
|
||||
class CSVReader
|
||||
{
|
||||
public:
|
||||
CSVReader();
|
||||
|
||||
static std::vector<OrderBookEntry> readCSV(std::string csvFile);
|
||||
static std::vector<std::string> tokenise(std::string csvLine, char separator);
|
||||
|
||||
static OrderBookEntry stringsToOBE(std::string price,
|
||||
std::string amount,
|
||||
std::string timestamp,
|
||||
std::string product,
|
||||
OrderBookType OrderBookType);
|
||||
|
||||
private:
|
||||
static OrderBookEntry stringsToOBE(std::vector<std::string> strings);
|
||||
|
||||
};
|
||||
@ -0,0 +1,232 @@
|
||||
#include "MerkelMain.h"
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include "OrderBookEntry.h"
|
||||
#include "CSVReader.h"
|
||||
|
||||
MerkelMain::MerkelMain()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void MerkelMain::init()
|
||||
{
|
||||
int input;
|
||||
currentTime = orderBook.getEarliestTime();
|
||||
|
||||
wallet.insertCurrency("BTC", 10);
|
||||
|
||||
while(true)
|
||||
{
|
||||
printMenu();
|
||||
input = getUserOption();
|
||||
processUserOption(input);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MerkelMain::printMenu()
|
||||
{
|
||||
// 1 print help
|
||||
std::cout << "1: Print help " << std::endl;
|
||||
// 2 print exchange stats
|
||||
std::cout << "2: Print exchange stats" << std::endl;
|
||||
// 3 make an offer
|
||||
std::cout << "3: Make an offer " << std::endl;
|
||||
// 4 make a bid
|
||||
std::cout << "4: Make a bid " << std::endl;
|
||||
// 5 print wallet
|
||||
std::cout << "5: Print wallet " << std::endl;
|
||||
// 6 continue
|
||||
std::cout << "6: Continue " << std::endl;
|
||||
|
||||
std::cout << "============== " << std::endl;
|
||||
|
||||
std::cout << "Current time is: " << currentTime << std::endl;
|
||||
}
|
||||
|
||||
void MerkelMain::printHelp()
|
||||
{
|
||||
std::cout << "Help - your aim is to make money. Analyse the market and make bids and offers. " << std::endl;
|
||||
}
|
||||
|
||||
void MerkelMain::printMarketStats()
|
||||
{
|
||||
for (std::string const& p : orderBook.getKnownProducts())
|
||||
{
|
||||
std::cout << "Product: " << p << std::endl;
|
||||
std::vector<OrderBookEntry> entries = orderBook.getOrders(OrderBookType::ask,
|
||||
p, currentTime);
|
||||
std::cout << "Asks seen: " << entries.size() << std::endl;
|
||||
std::cout << "Max ask: " << OrderBook::getHighPrice(entries) << std::endl;
|
||||
std::cout << "Min ask: " << OrderBook::getLowPrice(entries) << std::endl;
|
||||
|
||||
|
||||
|
||||
}
|
||||
// std::cout << "OrderBook contains : " << orders.size() << " entries" << std::endl;
|
||||
// unsigned int bids = 0;
|
||||
// unsigned int asks = 0;
|
||||
// for (OrderBookEntry& e : orders)
|
||||
// {
|
||||
// if (e.orderType == OrderBookType::ask)
|
||||
// {
|
||||
// asks ++;
|
||||
// }
|
||||
// if (e.orderType == OrderBookType::bid)
|
||||
// {
|
||||
// bids ++;
|
||||
// }
|
||||
// }
|
||||
// std::cout << "OrderBook asks: " << asks << " bids:" << bids << std::endl;
|
||||
|
||||
}
|
||||
|
||||
void MerkelMain::enterAsk()
|
||||
{
|
||||
std::cout << "Make an ask - enter the amount: product,price, amount, eg ETH/BTC,200,0.5" << std::endl;
|
||||
std::string input;
|
||||
std::getline(std::cin, input);
|
||||
|
||||
std::vector<std::string> tokens = CSVReader::tokenise(input, ',');
|
||||
if (tokens.size() != 3)
|
||||
{
|
||||
std::cout << "MerkelMain::enterAsk Bad input! " << input << std::endl;
|
||||
}
|
||||
else {
|
||||
try {
|
||||
OrderBookEntry obe = CSVReader::stringsToOBE(
|
||||
tokens[1],
|
||||
tokens[2],
|
||||
currentTime,
|
||||
tokens[0],
|
||||
OrderBookType::ask
|
||||
);
|
||||
obe.username = "simuser";
|
||||
if (wallet.canFulfillOrder(obe))
|
||||
{
|
||||
std::cout << "Wallet looks good. " << std::endl;
|
||||
orderBook.insertOrder(obe);
|
||||
}
|
||||
else {
|
||||
std::cout << "Wallet has insufficient funds . " << std::endl;
|
||||
}
|
||||
}catch (const std::exception& e)
|
||||
{
|
||||
std::cout << " MerkelMain::enterAsk Bad input " << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MerkelMain::enterBid()
|
||||
{
|
||||
std::cout << "Make an bid - enter the amount: product,price, amount, eg ETH/BTC,200,0.5" << std::endl;
|
||||
std::string input;
|
||||
std::getline(std::cin, input);
|
||||
|
||||
std::vector<std::string> tokens = CSVReader::tokenise(input, ',');
|
||||
if (tokens.size() != 3)
|
||||
{
|
||||
std::cout << "MerkelMain::enterBid Bad input! " << input << std::endl;
|
||||
}
|
||||
else {
|
||||
try {
|
||||
OrderBookEntry obe = CSVReader::stringsToOBE(
|
||||
tokens[1],
|
||||
tokens[2],
|
||||
currentTime,
|
||||
tokens[0],
|
||||
OrderBookType::bid
|
||||
);
|
||||
obe.username = "simuser";
|
||||
|
||||
if (wallet.canFulfillOrder(obe))
|
||||
{
|
||||
std::cout << "Wallet looks good. " << std::endl;
|
||||
orderBook.insertOrder(obe);
|
||||
}
|
||||
else {
|
||||
std::cout << "Wallet has insufficient funds . " << std::endl;
|
||||
}
|
||||
}catch (const std::exception& e)
|
||||
{
|
||||
std::cout << " MerkelMain::enterBid Bad input " << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MerkelMain::printWallet()
|
||||
{
|
||||
std::cout << wallet.toString() << std::endl;
|
||||
}
|
||||
|
||||
void MerkelMain::gotoNextTimeframe()
|
||||
{
|
||||
std::cout << "Going to next time frame. " << std::endl;
|
||||
for (std::string p : orderBook.getKnownProducts())
|
||||
{
|
||||
std::cout << "matching " << p << std::endl;
|
||||
std::vector<OrderBookEntry> sales = orderBook.matchAsksToBids(p, currentTime);
|
||||
std::cout << "Sales: " << sales.size() << std::endl;
|
||||
for (OrderBookEntry& sale : sales)
|
||||
{
|
||||
std::cout << "Sale price: " << sale.price << " amount " << sale.amount << std::endl;
|
||||
if (sale.username == "simuser")
|
||||
{
|
||||
// update the wallet
|
||||
wallet.processSale(sale);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
currentTime = orderBook.getNextTime(currentTime);
|
||||
}
|
||||
|
||||
int MerkelMain::getUserOption()
|
||||
{
|
||||
int userOption = 0;
|
||||
std::string line;
|
||||
std::cout << "Type in 1-6" << std::endl;
|
||||
std::getline(std::cin, line);
|
||||
try{
|
||||
userOption = std::stoi(line);
|
||||
}catch(const std::exception& e)
|
||||
{
|
||||
//
|
||||
}
|
||||
std::cout << "You chose: " << userOption << std::endl;
|
||||
return userOption;
|
||||
}
|
||||
|
||||
void MerkelMain::processUserOption(int userOption)
|
||||
{
|
||||
if (userOption == 0) // bad input
|
||||
{
|
||||
std::cout << "Invalid choice. Choose 1-6" << std::endl;
|
||||
}
|
||||
if (userOption == 1)
|
||||
{
|
||||
printHelp();
|
||||
}
|
||||
if (userOption == 2)
|
||||
{
|
||||
printMarketStats();
|
||||
}
|
||||
if (userOption == 3)
|
||||
{
|
||||
enterAsk();
|
||||
}
|
||||
if (userOption == 4)
|
||||
{
|
||||
enterBid();
|
||||
}
|
||||
if (userOption == 5)
|
||||
{
|
||||
printWallet();
|
||||
}
|
||||
if (userOption == 6)
|
||||
{
|
||||
gotoNextTimeframe();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "OrderBookEntry.h"
|
||||
#include "OrderBook.h"
|
||||
#include "Wallet.h"
|
||||
|
||||
|
||||
class MerkelMain
|
||||
{
|
||||
public:
|
||||
MerkelMain();
|
||||
/** Call this to start the sim */
|
||||
void init();
|
||||
private:
|
||||
void printMenu();
|
||||
void printHelp();
|
||||
void printMarketStats();
|
||||
void enterAsk();
|
||||
void enterBid();
|
||||
void printWallet();
|
||||
void gotoNextTimeframe();
|
||||
int getUserOption();
|
||||
void processUserOption(int userOption);
|
||||
|
||||
std::string currentTime;
|
||||
|
||||
// OrderBook orderBook{"20200317.csv"};
|
||||
OrderBook orderBook{"20200601.csv"};
|
||||
Wallet wallet;
|
||||
|
||||
};
|
||||
@ -0,0 +1,216 @@
|
||||
#include "OrderBook.h"
|
||||
#include "CSVReader.h"
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
/** construct, reading a csv data file */
|
||||
OrderBook::OrderBook(std::string filename)
|
||||
{
|
||||
orders = CSVReader::readCSV(filename);
|
||||
}
|
||||
|
||||
/** return vector of all know products in the dataset*/
|
||||
std::vector<std::string> OrderBook::getKnownProducts()
|
||||
{
|
||||
std::vector<std::string> products;
|
||||
|
||||
std::map<std::string,bool> prodMap;
|
||||
|
||||
for (OrderBookEntry& e : orders)
|
||||
{
|
||||
prodMap[e.product] = true;
|
||||
}
|
||||
|
||||
// now flatten the map to a vector of strings
|
||||
for (auto const& e : prodMap)
|
||||
{
|
||||
products.push_back(e.first);
|
||||
}
|
||||
|
||||
return products;
|
||||
}
|
||||
/** return vector of Orders according to the sent filters*/
|
||||
std::vector<OrderBookEntry> OrderBook::getOrders(OrderBookType type,
|
||||
std::string product,
|
||||
std::string timestamp)
|
||||
{
|
||||
std::vector<OrderBookEntry> orders_sub;
|
||||
for (OrderBookEntry& e : orders)
|
||||
{
|
||||
if (e.orderType == type &&
|
||||
e.product == product &&
|
||||
e.timestamp == timestamp )
|
||||
{
|
||||
orders_sub.push_back(e);
|
||||
}
|
||||
}
|
||||
return orders_sub;
|
||||
}
|
||||
|
||||
|
||||
double OrderBook::getHighPrice(std::vector<OrderBookEntry>& orders)
|
||||
{
|
||||
double max = orders[0].price;
|
||||
for (OrderBookEntry& e : orders)
|
||||
{
|
||||
if (e.price > max)max = e.price;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
|
||||
double OrderBook::getLowPrice(std::vector<OrderBookEntry>& orders)
|
||||
{
|
||||
double min = orders[0].price;
|
||||
for (OrderBookEntry& e : orders)
|
||||
{
|
||||
if (e.price < min)min = e.price;
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
std::string OrderBook::getEarliestTime()
|
||||
{
|
||||
return orders[0].timestamp;
|
||||
}
|
||||
|
||||
std::string OrderBook::getNextTime(std::string timestamp)
|
||||
{
|
||||
std::string next_timestamp = "";
|
||||
for (OrderBookEntry& e : orders)
|
||||
{
|
||||
if (e.timestamp > timestamp)
|
||||
{
|
||||
next_timestamp = e.timestamp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (next_timestamp == "")
|
||||
{
|
||||
next_timestamp = orders[0].timestamp;
|
||||
}
|
||||
return next_timestamp;
|
||||
}
|
||||
|
||||
void OrderBook::insertOrder(OrderBookEntry& order)
|
||||
{
|
||||
orders.push_back(order);
|
||||
std::sort(orders.begin(), orders.end(), OrderBookEntry::compareByTimestamp);
|
||||
}
|
||||
|
||||
std::vector<OrderBookEntry> OrderBook::matchAsksToBids(std::string product, std::string timestamp)
|
||||
{
|
||||
// asks = orderbook.asks
|
||||
std::vector<OrderBookEntry> asks = getOrders(OrderBookType::ask,
|
||||
product,
|
||||
timestamp);
|
||||
// bids = orderbook.bids
|
||||
std::vector<OrderBookEntry> bids = getOrders(OrderBookType::bid,
|
||||
product,
|
||||
timestamp);
|
||||
|
||||
// sales = []
|
||||
std::vector<OrderBookEntry> sales;
|
||||
|
||||
// I put in a little check to ensure we have bids and asks
|
||||
// to process.
|
||||
if (asks.size() == 0 || bids.size() == 0)
|
||||
{
|
||||
std::cout << " OrderBook::matchAsksToBids no bids or asks" << std::endl;
|
||||
return sales;
|
||||
}
|
||||
|
||||
// sort asks lowest first
|
||||
std::sort(asks.begin(), asks.end(), OrderBookEntry::compareByPriceAsc);
|
||||
// sort bids highest first
|
||||
std::sort(bids.begin(), bids.end(), OrderBookEntry::compareByPriceDesc);
|
||||
// for ask in asks:
|
||||
std::cout << "max ask " << asks[asks.size()-1].price << std::endl;
|
||||
std::cout << "min ask " << asks[0].price << std::endl;
|
||||
std::cout << "max bid " << bids[0].price << std::endl;
|
||||
std::cout << "min bid " << bids[bids.size()-1].price << std::endl;
|
||||
|
||||
for (OrderBookEntry& ask : asks)
|
||||
{
|
||||
// for bid in bids:
|
||||
for (OrderBookEntry& bid : bids)
|
||||
{
|
||||
// if bid.price >= ask.price # we have a match
|
||||
if (bid.price >= ask.price)
|
||||
{
|
||||
// sale = new order()
|
||||
// sale.price = ask.price
|
||||
OrderBookEntry sale{ask.price, 0, timestamp,
|
||||
product,
|
||||
OrderBookType::asksale};
|
||||
|
||||
if (bid.username == "simuser")
|
||||
{
|
||||
sale.username = "simuser";
|
||||
sale.orderType = OrderBookType::bidsale;
|
||||
}
|
||||
if (ask.username == "simuser")
|
||||
{
|
||||
sale.username = "simuser";
|
||||
sale.orderType = OrderBookType::asksale;
|
||||
}
|
||||
|
||||
// # now work out how much was sold and
|
||||
// # create new bids and asks covering
|
||||
// # anything that was not sold
|
||||
// if bid.amount == ask.amount: # bid completely clears ask
|
||||
if (bid.amount == ask.amount)
|
||||
{
|
||||
// sale.amount = ask.amount
|
||||
sale.amount = ask.amount;
|
||||
// sales.append(sale)
|
||||
sales.push_back(sale);
|
||||
// bid.amount = 0 # make sure the bid is not processed again
|
||||
bid.amount = 0;
|
||||
// # can do no more with this ask
|
||||
// # go onto the next ask
|
||||
// break
|
||||
break;
|
||||
}
|
||||
// if bid.amount > ask.amount: # ask is completely gone slice the bid
|
||||
if (bid.amount > ask.amount)
|
||||
{
|
||||
// sale.amount = ask.amount
|
||||
sale.amount = ask.amount;
|
||||
// sales.append(sale)
|
||||
sales.push_back(sale);
|
||||
// # we adjust the bid in place
|
||||
// # so it can be used to process the next ask
|
||||
// bid.amount = bid.amount - ask.amount
|
||||
bid.amount = bid.amount - ask.amount;
|
||||
// # ask is completely gone, so go to next ask
|
||||
// break
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// if bid.amount < ask.amount # bid is completely gone, slice the ask
|
||||
if (bid.amount < ask.amount &&
|
||||
bid.amount > 0)
|
||||
{
|
||||
// sale.amount = bid.amount
|
||||
sale.amount = bid.amount;
|
||||
// sales.append(sale)
|
||||
sales.push_back(sale);
|
||||
// # update the ask
|
||||
// # and allow further bids to process the remaining amount
|
||||
// ask.amount = ask.amount - bid.amount
|
||||
ask.amount = ask.amount - bid.amount;
|
||||
// bid.amount = 0 # make sure the bid is not processed again
|
||||
bid.amount = 0;
|
||||
// # some ask remains so go to the next bid
|
||||
// continue
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return sales;
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
#include "OrderBookEntry.h"
|
||||
#include "CSVReader.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class OrderBook
|
||||
{
|
||||
public:
|
||||
/** construct, reading a csv data file */
|
||||
OrderBook(std::string filename);
|
||||
/** return vector of all know products in the dataset*/
|
||||
std::vector<std::string> getKnownProducts();
|
||||
/** return vector of Orders according to the sent filters*/
|
||||
std::vector<OrderBookEntry> getOrders(OrderBookType type,
|
||||
std::string product,
|
||||
std::string timestamp);
|
||||
|
||||
/** returns the earliest time in the orderbook*/
|
||||
std::string getEarliestTime();
|
||||
/** returns the next time after the
|
||||
* sent time in the orderbook
|
||||
* If there is no next timestamp, wraps around to the start
|
||||
* */
|
||||
std::string getNextTime(std::string timestamp);
|
||||
|
||||
void insertOrder(OrderBookEntry& order);
|
||||
|
||||
std::vector<OrderBookEntry> matchAsksToBids(std::string product, std::string timestamp);
|
||||
|
||||
static double getHighPrice(std::vector<OrderBookEntry>& orders);
|
||||
static double getLowPrice(std::vector<OrderBookEntry>& orders);
|
||||
|
||||
private:
|
||||
std::vector<OrderBookEntry> orders;
|
||||
|
||||
|
||||
};
|
||||
@ -0,0 +1,31 @@
|
||||
#include "OrderBookEntry.h"
|
||||
|
||||
OrderBookEntry::OrderBookEntry( double _price,
|
||||
double _amount,
|
||||
std::string _timestamp,
|
||||
std::string _product,
|
||||
OrderBookType _orderType,
|
||||
std::string _username)
|
||||
: price(_price),
|
||||
amount(_amount),
|
||||
timestamp(_timestamp),
|
||||
product(_product),
|
||||
orderType(_orderType),
|
||||
username(_username)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
OrderBookType OrderBookEntry::stringToOrderBookType(std::string s)
|
||||
{
|
||||
if (s == "ask")
|
||||
{
|
||||
return OrderBookType::ask;
|
||||
}
|
||||
if (s == "bid")
|
||||
{
|
||||
return OrderBookType::bid;
|
||||
}
|
||||
return OrderBookType::unknown;
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
enum class OrderBookType{bid, ask, unknown, asksale, bidsale};
|
||||
|
||||
class OrderBookEntry
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
OrderBookEntry( double _price,
|
||||
double _amount,
|
||||
std::string _timestamp,
|
||||
std::string _product,
|
||||
OrderBookType _orderType,
|
||||
std::string username = "dataset");
|
||||
|
||||
static OrderBookType stringToOrderBookType(std::string s);
|
||||
|
||||
static bool compareByTimestamp(OrderBookEntry& e1, OrderBookEntry& e2)
|
||||
{
|
||||
return e1.timestamp < e2.timestamp;
|
||||
}
|
||||
static bool compareByPriceAsc(OrderBookEntry& e1, OrderBookEntry& e2)
|
||||
{
|
||||
return e1.price < e2.price;
|
||||
}
|
||||
static bool compareByPriceDesc(OrderBookEntry& e1, OrderBookEntry& e2)
|
||||
{
|
||||
return e1.price > e2.price;
|
||||
}
|
||||
|
||||
double price;
|
||||
double amount;
|
||||
std::string timestamp;
|
||||
std::string product;
|
||||
OrderBookType orderType;
|
||||
std::string username;
|
||||
};
|
||||
@ -0,0 +1,131 @@
|
||||
#include "Wallet.h"
|
||||
#include <iostream>
|
||||
#include "CSVReader.h"
|
||||
|
||||
Wallet::Wallet()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
void Wallet::insertCurrency(std::string type, double amount)
|
||||
{
|
||||
double balance;
|
||||
if (amount < 0)
|
||||
{
|
||||
throw std::exception{};
|
||||
}
|
||||
if (currencies.count(type) == 0) // not there yet
|
||||
{
|
||||
balance = 0;
|
||||
}
|
||||
else { // is there
|
||||
balance = currencies[type];
|
||||
}
|
||||
balance += amount;
|
||||
currencies[type] = balance;
|
||||
}
|
||||
|
||||
bool Wallet::removeCurrency(std::string type, double amount)
|
||||
{
|
||||
if (amount < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (currencies.count(type) == 0) // not there yet
|
||||
{
|
||||
//std::cout << "No currency for " << type << std::endl;
|
||||
return false;
|
||||
}
|
||||
else { // is there - do we have enough
|
||||
if (containsCurrency(type, amount))// we have enough
|
||||
{
|
||||
//std::cout << "Removing " << type << ": " << amount << std::endl;
|
||||
currencies[type] -= amount;
|
||||
return true;
|
||||
}
|
||||
else // they have it but not enough.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Wallet::containsCurrency(std::string type, double amount)
|
||||
{
|
||||
if (currencies.count(type) == 0) // not there yet
|
||||
return false;
|
||||
else
|
||||
return currencies[type] >= amount;
|
||||
|
||||
}
|
||||
|
||||
std::string Wallet::toString()
|
||||
{
|
||||
std::string s;
|
||||
for (std::pair<std::string,double> pair : currencies)
|
||||
{
|
||||
std::string currency = pair.first;
|
||||
double amount = pair.second;
|
||||
s += currency + " : " + std::to_string(amount) + "\n";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
bool Wallet::canFulfillOrder(OrderBookEntry order)
|
||||
{
|
||||
std::vector<std::string> currs = CSVReader::tokenise(order.product, '/');
|
||||
// ask
|
||||
if (order.orderType == OrderBookType::ask)
|
||||
{
|
||||
double amount = order.amount;
|
||||
std::string currency = currs[0];
|
||||
std::cout << "Wallet::canFulfillOrder " << currency << " : " << amount << std::endl;
|
||||
|
||||
return containsCurrency(currency, amount);
|
||||
}
|
||||
// bid
|
||||
if (order.orderType == OrderBookType::bid)
|
||||
{
|
||||
double amount = order.amount * order.price;
|
||||
std::string currency = currs[1];
|
||||
std::cout << "Wallet::canFulfillOrder " << currency << " : " << amount << std::endl;
|
||||
return containsCurrency(currency, amount);
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Wallet::processSale(OrderBookEntry& sale)
|
||||
{
|
||||
std::vector<std::string> currs = CSVReader::tokenise(sale.product, '/');
|
||||
// ask
|
||||
if (sale.orderType == OrderBookType::asksale)
|
||||
{
|
||||
double outgoingAmount = sale.amount;
|
||||
std::string outgoingCurrency = currs[0];
|
||||
double incomingAmount = sale.amount * sale.price;
|
||||
std::string incomingCurrency = currs[1];
|
||||
|
||||
currencies[incomingCurrency] += incomingAmount;
|
||||
currencies[outgoingCurrency] -= outgoingAmount;
|
||||
|
||||
}
|
||||
// bid
|
||||
if (sale.orderType == OrderBookType::bidsale)
|
||||
{
|
||||
double incomingAmount = sale.amount;
|
||||
std::string incomingCurrency = currs[0];
|
||||
double outgoingAmount = sale.amount * sale.price;
|
||||
std::string outgoingCurrency = currs[1];
|
||||
|
||||
currencies[incomingCurrency] += incomingAmount;
|
||||
currencies[outgoingCurrency] -= outgoingAmount;
|
||||
}
|
||||
}
|
||||
std::ostream& operator<<(std::ostream& os, Wallet& wallet)
|
||||
{
|
||||
os << wallet.toString();
|
||||
return os;
|
||||
}
|
||||
|
||||
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "OrderBookEntry.h"
|
||||
#include <iostream>
|
||||
|
||||
class Wallet
|
||||
{
|
||||
public:
|
||||
Wallet();
|
||||
/** insert currency to the wallet */
|
||||
void insertCurrency(std::string type, double amount);
|
||||
/** remove currency from the wallet */
|
||||
bool removeCurrency(std::string type, double amount);
|
||||
|
||||
/** check if the wallet contains this much currency or more */
|
||||
bool containsCurrency(std::string type, double amount);
|
||||
/** checks if the wallet can cope with this ask or bid.*/
|
||||
bool canFulfillOrder(OrderBookEntry order);
|
||||
/** update the contents of the wallet
|
||||
* assumes the order was made by the owner of the wallet
|
||||
*/
|
||||
void processSale(OrderBookEntry& sale);
|
||||
|
||||
|
||||
/** generate a string representation of the wallet */
|
||||
std::string toString();
|
||||
friend std::ostream& operator<<(std::ostream& os, Wallet& wallet);
|
||||
|
||||
|
||||
private:
|
||||
std::map<std::string,double> currencies;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
#include "Wallet.h"
|
||||
#include <iostream>
|
||||
#include "MerkelMain.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
MerkelMain app{};
|
||||
app.init();
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user