This project is about creating a rudimentary market for cryptocurrencies. A class, name "Exchange", has public member functions that allow for the deposit and withdrawl of various assets (e.g. Bitcoin, Etherum and US Dollars). Orders to buy and sell assets at a specified price can also be made and the exchange will perform trades as possible to fulfill orders. Lastly, the exchange has a member function dedicated to printing out the current status of the exchange (i.e. what is in each user’s portfolio, what orders have been opened and filled, what trades have taken place, and what the current prices are for the assets being traded.
The starter code has three header files and 4 implementation files. Some of these files have content in them already, but you are welcome to add, remove or change any part of the code given. Each test case will compile the implementation files and include the exchange.hpp and/or utility.hpp if it makes use of a class declared within. The useraccount files are not directly tested in the test cases, but they can be optionally used to store and manipulate information associated with a user’s account (as helper class(es) for the exchange). The provided main file is never used by any test cases, but it provides an example use of the exchange for your own testing purposes.

main.cpp:
#include <iostream>
#include <map>
#include <string>
#include <vector>

#include "exchange.hpp"
#include "useraccount.hpp"
#include "utility.hpp"

int main() {
  std::cout << "start" << std::endl;

  Exchange base;
  base.MakeDeposit("Nahum", "USD", 1000);
  base.MakeDeposit("Nahum", "ETH", 400);
  base.MakeDeposit("Dolson", "BTC", 100);
  base.MakeDeposit("Dolson", "USD", 7000);
  base.MakeDeposit("Enbody", "USD", 7000);
  base.MakeDeposit("Ofria", "BCH", 9);
  base.MakeWithdrawal("Dolson", "BTC", 10);
  base.PrintUserPortfolios(std::cout);
  std::cout << std::endl;
  Order o_n{"Nahum", "Buy", "BTC", 2, 22};
  Order o_d{"Dolson", "Sell", "BTC", 3, 17};
  std::cout << "Before 1st add order" << std::endl;

  base.AddOrder(o_n);
  std::cout << "After 1st add order" << std::endl;
  base.PrintUsersOrders(std::cout);

  std::cout << std::endl;

  std::cout << "Before 2nd add order" << std::endl;

  base.AddOrder(o_d);

  std::cout << "After 2nd add order" << std::endl;

  base.PrintTradeHistory(std::cout);
  std::cout << std::endl;
  base.PrintUserPortfolios(std::cout);
  std::cout << std::endl;
  base.PrintUsersOrders(std::cout);
  std::cout << std::endl;
  base.AddOrder({"Dolson", "Buy", "ETH", 10, 200});
  base.AddOrder({"Enbody", "Buy", "ETH", 15, 300});
  base.AddOrder({"Nahum", "Sell", "ETH", 20, 100});

  base.PrintTradeHistory(std::cout);
  base.PrintUsersOrders(std::cout);
  base.AddOrder({"Nahum", "Sell", "ETH", 20, 1000});
  base.AddOrder({"Dolson", "Sell", "ETH", 2, 250});
  base.AddOrder({"Enbody", "Buy", "BTC", 1, 10});
  base.PrintTradeHistory(std::cout);
  base.PrintUserPortfolios(std::cout);
  std::cout << std::endl << std::endl;
  base.PrintUsersOrders(std::cout);
  base.AddOrder({"Enbody", "Buy", "LTC", 1, 10});
  base.AddOrder({"Ofria", "Sell", "BCH", 2, 55});
  base.PrintBidAskSpread(std::cout);

  return 0;
}

exchange.cpp:
#include "exchange.hpp"


exchange.hpp:
#pragma once
#include <iostream>
#include <string>

#include "useraccount.hpp"
#include "utility.hpp"

class Exchange {
 public:
  void MakeDeposit(const std::string &username, const std::string &asset,
                   int amount);
  void PrintUserPortfolios(std::ostream &os) const;
  bool MakeWithdrawal(const std::string &username, const std::string &asset,
                      int amount);
  bool AddOrder(const Order &order);
  void PrintUsersOrders(std::ostream &os) const;
  void PrintTradeHistory(std::ostream &os) const;
  void PrintBidAskSpread(std::ostream &os) const;
};

useraccount.cpp:
#include "useraccount.hpp"


useraccount.hpp:
#pragma once

utility.cpp:
#include "utility.hpp"

utility.hpp:
#pragma once
#include <iostream>
#include <string>

struct Order {
  std::string username;
  std::string side;  // Can be "Buy" or "Sell"
  std::string asset;
  int amount;
  int price;
};

struct Trade {
  std::string buyer_username;
  std::string seller_username;
  std::string asset;
  int amount;
  int price;
};


Please write these Exchange member functions:
MakeDeposit: this function should take a username (e.g. Prof), an asset (e.g. “BTC”), and an amount (e.g. 100). The function does not return anything, but should store the information that the deposit occurred to a user’s portfolio. A portfolio is a record of the assets a user possesses on the exchange that are not involved in any open orders. In the example, Prof is depositing 100 BTC (Bitcoins) into the exchange.
PrintUserPortfolios: this function takes a reference to a std::ostream and should print out each user’s portfolio (ordered alphabetically by user’s name, and then by asset). Remember that assets that are involved in an open order should not be part of a user’s portfolio. Please see the test cases for exact formatting. Most test cases involving printing will print to std::cout (for easier output reading), as well as, to a std::ostringstream (for test case validation).
MakeWithdrawl: this function has the same parameters as MakeDeposit, but instead of depositing funds in the exchange, the user is removing previously deposited funds. The function returns true if and only if the withdrawal was successful. A withdrawal can only be unsuccessful if there are insufficient assets in a user’s portfolio.
AddOrder: This is the most involved member function here. All of the code needed to implement this functionality should not be in this single function but allocated to many helper functions and classes. This function takes an Order (declared in utility.hpp) and returns true if the order was successfully placed. The only reason an order could not be placed is if there were insufficient assets to cover the trade. For instance, if you want to sell 10 bitcoins you must have at least 10 bitcoins in your portfolio. Additionally, if you want to buy 10 bitcoins for 100 USD (US Dollars), you need to have at least 1000 dollars in your portfolio to pay for such an order. All orders (buy or sell) are priced in USD. When an order is made, the funds needed to cover the order are removed from the portfolio (to prevent double spending). The order is then considered open and may participate market taker trades and then market maker trades (details on trading provided below).
PrintUserOrders: For each user (ordered alphabetically), this function prints the open and filled trades (ordered chronologically as each trade was opened/filled) to the referenced std::ostream. See test cases for exact formatting.
PrintTradeHistory: Prints a record of each trade (chronologically) that occurred to the provided reference to std::ostream. See test cases for exact formatting.
PrintBidAskSpread: For each asset (ordered alphabetically), prints the bid ask spread dictated by the open orders to the reference to std::ostream. See test cases for exact formatting.