Add Initial commit to integrate to the main app enterAsk

This commit is contained in:
Lev
2021-06-12 22:19:11 -05:00
parent 279051e997
commit ae736454ec
13 changed files with 4355 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,104 @@
#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;
}

View File

@ -0,0 +1,24 @@
#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);
};

View File

@ -0,0 +1,169 @@
#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 ask " << 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;
}
}
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
);
orderBook.insertOrder(obe);
}catch (const std::exception& e)
{
std::cout << " MerkelMain::enterAsk Bad input " << std::endl;
}
}
std::cout << "You typed: " << input << std::endl;
}
void MerkelMain::enterBid()
{
std::cout << "Make a bid - enter the amount" << std::endl;
}
void MerkelMain::printWallet()
{
std::cout << "Your wallet is empty. " << std::endl;
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;
}
}
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();
}
}

View File

@ -0,0 +1,30 @@
#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"};
Wallet wallet;
};

View File

@ -0,0 +1,196 @@
#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;
// 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)
{
//std::cout << "Ask p: " << ask.price << " a: " << ask.amount << std::endl;
// for bid in bids:
for (OrderBookEntry& bid : bids)
{
//std::cout << "bid p: " << bid.price << " a: " << bid.amount << std::endl;
// if bid.price >= ask.price # we have a match
if (bid.price >= ask.price)
{
std::cout << "bid price is right " << std::endl;
// sale = new order()
// sale.price = ask.price
OrderBookEntry sale{ask.price, 0, timestamp, product, OrderBookType::sale};
// # 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)
{
// 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;
}

View File

@ -0,0 +1,37 @@
#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;
};

View File

@ -0,0 +1,28 @@
#include "OrderBookEntry.h"
OrderBookEntry::OrderBookEntry( double _price,
double _amount,
std::string _timestamp,
std::string _product,
OrderBookType _orderType)
: price(_price),
amount(_amount),
timestamp(_timestamp),
product(_product),
orderType(_orderType)
{
}
OrderBookType OrderBookEntry::stringToOrderBookType(std::string s)
{
if (s == "ask")
{
return OrderBookType::ask;
}
if (s == "bid")
{
return OrderBookType::bid;
}
return OrderBookType::unknown;
}

View File

@ -0,0 +1,37 @@
#pragma once
#include <string>
enum class OrderBookType{bid, ask, unknown, sale};
class OrderBookEntry
{
public:
OrderBookEntry( double _price,
double _amount,
std::string _timestamp,
std::string _product,
OrderBookType _orderType);
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;
};

View File

@ -0,0 +1,90 @@
#include "Wallet.h"
#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 in wallet yet
{
balance = 0;
}
else
{
balance = currencies[type];
}
balance += amount;
currencies[type] = balance;
}
bool Wallet::removeCurrency(std::string type, double amount)
{
double balance;
if(amount < 0)
{
return false;
}
if(currencies.count(type) == 0) // currency not in wallet
{
return false;
}
else // is there, do we have enough?
{
if(containsCurrency(type, amount))
{
currencies[type] -= amount;
return true;
}
else // didn't have enough
return false;
}
}
bool Wallet::containsCurrency(std::string type, double amount)
{
if(currencies.count(type) == 0) // not in wallet yet
{
return false;
}
else
return currencies[type] >= amount;
}
std::string Wallet::toString()
{
std::string s;
for(std::pair<const 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];
return containsCurrency(currency, amount);
}
if(order.orderType == OrderBookType::bid)
{
double amount = order.amount * order.price;
std::string currency = currs[1];
return containsCurrency(currency, amount);
}
return false;
}

View File

@ -0,0 +1,28 @@
#pragma once
#include <string>
#include <map>
#include "OrderBookEntry.h"
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 at least this much currency */
bool containsCurrency(std::string type, double amount);
/** check if the wallet can cope with the ask or bid */
bool canFulfillOrder(OrderBookEntry order);
/** generate a string representation of the wallet */
std::string toString();
private:
std::map<std::string, double> currencies;
};

View File

@ -0,0 +1,63 @@
#include <iostream>
#include <string>
#include <vector>
#include "OrderBookEntry.h"
#include "MerkelMain.h"
#include "CSVReader.h"
#include "Wallet.h"
int main()
{
//MerkelMain app{};
//app.init();
Wallet wallet;
wallet.insertCurrency("BTC", 10);
wallet.insertCurrency("USDT", 100.83);
std::cout << wallet.toString() << std::endl;
//std::cout << "Wallet has BTC " << wallet.containsCurrency("USDT", 100.50) << std::endl;
wallet.removeCurrency("USDT", 10);
std::cout << wallet.toString() << std::endl;
//CSVReader::readCSV("20200317.csv");
}
// std::vector<OrderBookEntry> orders;
// orders.push_back( OrderBookEntry{1000,
// 0.02,
// "2020/03/17 17:01:24.884492",
// "BTC/USDT",
// OrderBookType::bid} );
// orders.push_back( OrderBookEntry{2000,
// 0.02,
// "2020/03/17 17:01:24.884492",
// "BTC/USDT",
// OrderBookType::bid} );
// // std::cout << "The price is " << orders[1].price << std::endl;
// for (OrderBookEntry& order : orders)
// {
// std::cout << "The price is " << order.price << std::endl;
// }
// for (unsigned int i = 0; i < orders.size() ; ++i)
// {
// std::cout << "The price is " << orders[i].price << std::endl;
// }
// for (unsigned int i = 0; i < orders.size() ; ++i)
// {
// std::cout << "The price is " << orders.at(i).price << std::endl;
// }