订单路由系统的实现

Create a solution for maintaining information about orders that are being placed on an exchange by an order router. This should derive from
IOrderManager (provided in challenge.h).
The in-house trading system tracks orders using a unique internal identifier (provided in challenge.h). The exchange tracks orders using a unique
text identifier.
Each order has a price and a quantity. Both are uint32_t. Prices and quantities must be positive numbers.
When an order request operation is received from a trader, the order manager must be able to store and retrieve information using the
OrderIdentifier.
When a response is received from the exchange the order manager must be able to retrieve the information using the text identifier.
The trader can perform the following requests. Each of these includes the OrderIdentifier but not the exchange's identifier:
Enter order. Includes OrderIdentifier, price and quantity but not exchange's identifier (this is provided when the exchange confirms the
order).
Cancel order. Only the OrderIdentifier is provided. The order is considered as still in the market until the exchange confirms the
cancellation.
The exchange can provide the following updates:
New order confirmed. Contains both the OrderIdentifier and the exchange's text identifier.
Order traded. Includes quantity traded and exchange's identifier.
Order cancelled. This can be due to the trader cancelling it, or the exchange cancelling the order. Contains only exchange's identifier.
If all the order quantity is traded then the order should be considered to be removed from the market and stops being active. An order can be
traded multiple times until all its quantity is used up.
The trader must not reuse a previously used order identifier, and they are only allowed cancel an order which is active in the market and which
they haven't already sent a cancel request for.
An order becomes active when the exchange confirms it, and stops being active when the exchange provides a cancel update on the order or a
trade update which uses all of the remaining quantity of the order.
Requests and updates have restrictions in the sequence in which they can occur for a specific order. Here A->B means that B can only occur after
A, if it occurs. There are no restrictions on sequencing between different orders.
Enter order -> New order confirmed
New order confirmed -> Order traded
New order confirmed -> Order cancelled
Order traded -> Order cancelled
You can assume the exchange never sends incorrect information, for instance a trade greater than the order quantity or a cancellation for an
order which doesn't exist.
Your order manager solution should handle requests from the trader and responses from the exchange in the form of methods being called in the
class you derive from IOrderManager. You are free to create other classes as part of the solution.
Please include explanatory comments describing why you chose to design each part of the solution in the way you did, plus a description of your
testing methods. If you discover ambiguities in the challenge, describe what assumptions you have made to allow you to continue.
Put all your files in an archive along with instructions how to build and run it.

#pragma once

#include <stdint.h>
#include <string>
#include <map>

// company's order identifier
struct OrderIdentifier {
    OrderIdentifier() = default;
    
    OrderIdentifier(uint16_t m, uint16_t d, uint16_t t, uint32_t s)
    : _market(m)
    , _desk(d)
    , _trader(t)
    , _sequence(s)
    {}

    uint16_t _market{0};
    uint16_t _desk{0};
    uint16_t _trader{0};
    uint32_t _sequence{0}; // increments with each order from a particular trader

    bool operator < (OrderIdentifier const& id) const  
    { 
        // construct key, assume each para takes up 8 bits
        uint32_t key1 = (_market << 24) | (_desk << 16) | (_trader << 8) | _sequence;
        uint32_t key2 = (id._market << 24) | (id._desk << 16) | (id._trader << 8) | id._sequence;

        return  (key1 < key2) ? true : false;
    } 
};

// company's order
struct Order {

    enum orderStatus{
        ORDER_STATUS_ENTER     = 0,
        ORDER_STATUS_CONFIRMED = 1,
        ORDER_STATUS_TRADED    = 2,
        ORDER_STATUS_CANCELLED = 3,
        ORDER_STATUS_MAX
    };

    Order() = default;
    
    Order(uint32_t p, uint32_t q) : _price(p), _quantity(q){}

    uint32_t    _price{0};                      // order price
    uint32_t    _quantity{0};                   // order quantity
    bool        _isActive{false};               // order active or not
    bool        _isCancelled{false};            // order cancelled by trader or not
    orderStatus _status{ORDER_STATUS_ENTER};    // order status
};

//
// The order router will call these methods as it receives order operations from the
// trader and exchange.
// Note:
// 1. Thread safety needs to be considered for your implementation of this class: e.g.
// - OnTraderXXX may be called from different threads
// - You can assume OnExchangeXXX will only be called from a single thread.
// - But OnTraderXXX and OnExchangeXXX maybe called from different threads.
// 2. Performance, in terms of latency, of all the interface functions are important.
//
class IOrderManager
{
public:
    // trader operations - these return false if there is a problem
    virtual bool OnTraderEnter(const OrderIdentifier& aInternal, uint32_t aPrice, uint32_t aQuantity) = 0;
    virtual bool OnTraderCancel(const OrderIdentifier& aInternal) = 0;

    // exchange operations - these return false if there is a problem
    virtual bool OnExchangeNew(const OrderIdentifier& aInternal, const std::string& aExternal) = 0;
    virtual bool OnExchangeTrade(const std::string& aExternal, uint32_t aQuantity) = 0;
    virtual bool OnExchangeCancel(const std::string& aExternal) = 0;

    virtual bool IsOrderActive(const OrderIdentifier& aInternal) const = 0;
    virtual bool IsOrderActive(const std::string& aExternal) const = 0;

    // returns the quantity of the order that is active in the market, or zero if the order isn't
    // recognised or is not active
    virtual uint32_t GetActiveOrderQuantity(const OrderIdentifier& aInternal) const = 0;
};

// order manager solution derived from IOrderManager
class OrderManager : public IOrderManager
{
public:

    OrderManager() = default;
    virtual ~OrderManager(){};

    // get mOrdersHistory key from order identifier
    inline uint32_t getKey(const OrderIdentifier& aInternal) const
    {  
        return (aInternal._market << 24) | (aInternal._desk << 16) 
              | (aInternal._trader << 8) | aInternal._sequence;
    }
    
    // trader operations - these return false if there is a problem
    virtual bool OnTraderEnter(const OrderIdentifier& aInternal, uint32_t aPrice, uint32_t aQuantity);
    virtual bool OnTraderCancel(const OrderIdentifier& aInternal);

    // exchange operations - these return false if there is a problem
    virtual bool OnExchangeNew(const OrderIdentifier& aInternal, const std::string& aExternal);
    virtual bool OnExchangeTrade(const std::string& aExternal, uint32_t aQuantity);
    virtual bool OnExchangeCancel(const std::string& aExternal);

    virtual bool IsOrderActive(const OrderIdentifier& aInternal) const;
    virtual bool IsOrderActive(const std::string& aExternal) const;

    // returns the quantity of the order that is active in the market, or zero if the order isn't
    // recognised or is not active
    virtual uint32_t GetActiveOrderQuantity(const OrderIdentifier& aInternal) const;

public:

    /**************************************************************************
    * 1.store all history order in mOrdersHistory, to stop trader from reusing a
    *   previous order identifier
    * 2.when reponse from exchange, to get order identifier from order identifier
    *   so that only one copy of order exists
    * 3.use unordered_map so an order can be found with low latency
    ***************************************************************************/
    std::unordered_map<std::string, OrderIdentifier> mOrdersInMarket; // all order in market
    std::unordered_map<uint32_t, Order>              mOrdersHistory;  // all order in history
};
#include "challenge.h"
#include "assert.h"
#include <mutex>

std::mutex mutexForOrder;  // order mutex

/*
********************************************************************
* Desc: insert an order in mOrdersInMarket if not exist
*       status:  ORDER_STATUS_ENTER
*********************************************************************
*/
bool OrderManager::OnTraderEnter(const OrderIdentifier& aInternal, uint32_t aPrice, uint32_t aQuantity)
{
    std::lock_guard<std::mutex> lck(mutexForOrder);
    uint32_t key = getKey(aInternal);
    // trader must not reuse a previously used order identifier
    std::map<uint32_t, Order>::iterator it = mOrdersHistory.find(key);
    if (it != mOrdersHistory.end())
    {
        return false;
    }

    Order order(aPrice, aQuantity);
    mOrdersHistory.insert(std::pair<uint32_t, Order>(key, order));

    return true;
}

/*
********************************************************************
* Desc: cancel an order active in the market or not cancelled before
*       status:  ORDER_STATUS_CONFIRMED  ->  ORDER_STATUS_CANCELLED
*                ORDER_STATUS_TRADED     ->  ORDER_STATUS_CANCELLED
*********************************************************************
*/
bool OrderManager::OnTraderCancel(const OrderIdentifier& aInternal)
{
    std::lock_guard<std::mutex> lck(mutexForOrder);
    uint32_t key = getKey(aInternal);
    // cancel an order not exist
    std::map<uint32_t, Order>::iterator it = mOrdersHistory.find(key);
    if (it == mOrdersHistory.end())
    {
        return false;
    }

    // order cancelld before
    if (it->second._isCancelled == true)
    {
        return false;
    }

    // order not active 
    if (it->second._isActive == false)
    {
        return false;
    }

    // order status invalid
    if (it->second._status != Order::ORDER_STATUS_CONFIRMED && it->second._status != Order::ORDER_STATUS_TRADED)
    {
        return false;
    }

    // update order status
    it->second._isCancelled = true;
    it->second._status      = Order::ORDER_STATUS_CANCELLED;

    return true;
}


/*
********************************************************************
* Desc: insert an order in mText2Internal, and update order status
*       status:  ORDER_STATUS_ENTER  ->  ORDER_STATUS_CONFIRMED
*********************************************************************
*/
bool OrderManager::OnExchangeNew(const OrderIdentifier& aInternal, const std::string& aExternal)
{
    std::lock_guard<std::mutex> lck(mutexForOrder);
    uint32_t key = getKey(aInternal);
    std::map<uint32_t, Order>::iterator it = mOrdersHistory.find(key);
    if (it == mOrdersHistory.end())
    {
        return false;
    }

    // ignore a history order
    if (Order::ORDER_STATUS_MAX == it->second._status)
    {
        return false;
    }

    it->second._status   = Order::ORDER_STATUS_CONFIRMED;
    it->second._isActive = true;
    
    // update order status
    it->second._status   = Order::ORDER_STATUS_CONFIRMED;
    it->second._isActive = true;

    // update mOrdersInMarket, not record key to keep OrderIdentifier information
    mOrdersInMarket.insert(std::pair<std::string, OrderIdentifier>(aExternal, aInternal));

    return true;
}

/*
********************************************************************
* Desc: Trade by aQuantity, and update order status
*       if quantity used up, erase order
*       status:  ORDER_STATUS_CONFIRMED  ->  ORDER_STATUS_TRADED
*********************************************************************
*/
bool OrderManager::OnExchangeTrade(const std::string& aExternal, uint32_t aQuantity)
{
    std::lock_guard<std::mutex> lck(mutexForOrder);
    // find OrderIdentifier in mOrdersInMarket by exchange's identifier
    std::map<std::string, OrderIdentifier>::iterator iter = mOrdersInMarket.find(aExternal);
    if (iter == mOrdersInMarket.end())
    {
        return false;
    }

    // find order in mOrdersHistory by key
    uint32_t key = getKey(iter->second);
    std::map<uint32_t, Order>::iterator it = mOrdersHistory.find(key);

    // order not exist
    if (it == mOrdersHistory.end())
    {
        return false;
    }

    // status invalid
    if (it->second._status != Order::ORDER_STATUS_CONFIRMED && it->second._status != Order::ORDER_STATUS_TRADED)
    {
        return false;
    }

    // aQuantity invalid
    if (aQuantity > it->second._quantity)
    {
        return false;
    }

    // update order status
    it->second._quantity -= aQuantity;
    if (0 != it->second._quantity)
    {
        it->second._status = Order::ORDER_STATUS_TRADED;
    }
    else
    {
        // remove from market
        mOrdersInMarket.erase(aExternal);  
        it->second._status      = Order::ORDER_STATUS_MAX;
        it->second._isActive    = false;
        it->second._isCancelled = true;
    }

    return true;
}

/*
********************************************************************
* Desc: Cancelled by Exchange
*       status:  ORDER_STATUS_CANCELLED  ->  ORDER_STATUS_ENTER
*********************************************************************
*/
bool OrderManager::OnExchangeCancel(const std::string& aExternal)
{
    std::lock_guard<std::mutex> lck(mutexForOrder);
    // find OrderIdentifier in mOrdersInMarket by exchange's identifier
    std::map<std::string, OrderIdentifier>::iterator iter = mOrdersInMarket.find(aExternal);
    if (iter == mOrdersInMarket.end())
    {
        return false;
    }

    // find order in mOrdersHistory by key
    uint32_t key = getKey(iter->second);
    std::map<uint32_t, Order>::iterator it = mOrdersHistory.find(key);

    // order not exist
    if (it == mOrdersHistory.end())
    {
        return false;
    }

    // status invalid
    if (it->second._status != Order::ORDER_STATUS_CANCELLED)
    {
        return false;
    }

    // update order status
    mOrdersInMarket.erase(aExternal);
    it->second._status      = Order::ORDER_STATUS_MAX;
    it->second._isActive    = false;
    it->second._isCancelled = true;

    return true;
}

bool OrderManager::IsOrderActive(const OrderIdentifier& aInternal) const
{
    std::lock_guard<std::mutex> lck(mutexForOrder);
    uint32_t key = getKey(aInternal);
    std::map<uint32_t, Order>::const_iterator it = mOrdersHistory.find(key);
    if (it == mOrdersHistory.end())
    {
        return false;
    }

    return it->second._isActive;
}

bool OrderManager::IsOrderActive(const std::string& aExternal) const
{
    std::lock_guard<std::mutex> lck(mutexForOrder);
    // find OrderIdentifier in mOrdersInMarket by exchange's identifier
    std::map<std::string, OrderIdentifier>::const_iterator iter = mOrdersInMarket.find(aExternal);
    if (iter == mOrdersInMarket.end())
    {
        return false;
    }

    // find order in mOrdersHistory by key
    uint32_t key = getKey(iter->second);
    std::map<uint32_t, Order>::const_iterator it = mOrdersHistory.find(key);

    // order not exist
    if (it == mOrdersHistory.end())
    {
        return false;
    }

    return it->second._isActive;
}

/*
********************************************************************
* Desc: get order quantity, if not exist, return 0
*********************************************************************
*/
uint32_t OrderManager::GetActiveOrderQuantity(const OrderIdentifier& aInternal) const
{
    std::lock_guard<std::mutex> lck(mutexForOrder);
    uint32_t key = getKey(aInternal);
    std::map<uint32_t, Order>::const_iterator it = mOrdersHistory.find(key);
    if (it == mOrdersHistory.end())
    {
        return 0;
    }

    if (false == it->second._isActive)
    {
        return 0;
    }

    return it->second._quantity;
}

// test normal flow
void testCase01()
{
    OrderIdentifier id1(0, 0, 0, 0);
    OrderIdentifier id2(0, 0, 0, 1);
    OrderIdentifier id3(0, 0, 0, 2);
    OrderIdentifier id4(0, 0, 0, 0);
    OrderIdentifier id5(0, 0, 0, 5);

    OrderManager mgr; 

    // on trader enter
    assert(true  == mgr.OnTraderEnter(id1, 2, 10)); // valid input
    assert(true  == mgr.OnTraderEnter(id2, 3, 20)); // valid input
    assert(true  == mgr.OnTraderEnter(id3, 4, 5));  // valid input
    assert(false == mgr.OnTraderEnter(id4, 2, 11)); // invalid input
    assert(3 == mgr.mOrdersHistory.size());         // check order count

    uint32_t key1 = mgr.getKey(id1);
    std::map<uint32_t, Order>::iterator it = mgr.mOrdersHistory.find(key1);
    assert(Order::ORDER_STATUS_ENTER == it->second._status);  // check order status

    // on exchane new 
    assert(false == mgr.OnExchangeNew(id5, "id5"));  // invalid input
    assert(true == mgr.OnExchangeNew(id1, "id1"));   // valid input
    assert(1 == mgr.mOrdersInMarket.size());         // check count

    it = mgr.mOrdersHistory.find(key1);
    assert(Order::ORDER_STATUS_CONFIRMED == it->second._status);  // check order status
    assert(true == it->second._isActive);  // check active

    // on exchange trade
    assert(false == mgr.OnExchangeTrade("id5", 1));   // order not exist
    assert(false == mgr.OnExchangeTrade("id2", 1));   // order status err
    assert(false == mgr.OnExchangeTrade("id1", 100)); // order quantity invalid
    assert(true  == mgr.OnExchangeTrade("id1", 1));   // valid input
    
    it = mgr.mOrdersHistory.find(key1);
    assert(Order::ORDER_STATUS_TRADED == it->second._status); // check order status
    assert(9 == it->second._quantity);                        // chekc order quantity

    // is order active
    assert(true  == mgr.IsOrderActive("id1"));   // valid
    assert(false == mgr.IsOrderActive("id2"));   // invalid
    assert(false == mgr.IsOrderActive("id5"));   // order not exist

    assert(true  == mgr.IsOrderActive(id1));    // valid
    assert(false == mgr.IsOrderActive(id2));    // invalid
    assert(false == mgr.IsOrderActive(id5));    // invalid

    // get order quantity
    assert(9 == mgr.GetActiveOrderQuantity(id1));  // order active
    assert(0 == mgr.GetActiveOrderQuantity(id2));  // order inactive
    assert(0 == mgr.GetActiveOrderQuantity(id2));  // order not exits

    // on exchange trade
    assert(true  == mgr.OnExchangeTrade("id1", 9)); // valid input
    assert(3 == mgr.mOrdersHistory.size());         // check order count
    assert(true == mgr.mOrdersInMarket.empty());    // check count

    // on exchange new
    assert(false == mgr.OnExchangeNew(id1, "id1"));   // a history order
    assert(true  == mgr.OnExchangeNew(id2, "id2"));   // valid input

    // on trader cancel
    assert(false == mgr.OnTraderCancel(id3));  // cancel an invalid order
    assert(true  == mgr.OnTraderCancel(id2));  // valid input
    uint32_t key2 = mgr.getKey(id2);
    it = mgr.mOrdersHistory.find(key2);
    assert(Order::ORDER_STATUS_CANCELLED == it->second._status); // check order status
    assert(true  == it->second._isActive);     // check active
    assert(true  == it->second._isCancelled);  // check cancelled or not
    assert(false == mgr.OnTraderCancel(id2));  // order cancelled before

    // on exchane cancel
    assert(false == mgr.OnExchangeCancel("id3"));  // invalid input
    assert(true  == mgr.OnExchangeCancel("id2"));  // valid input
    assert(false == it->second._isActive);         // check active
    assert(true  == it->second._isCancelled);      // check cancelled or not
    assert(Order::ORDER_STATUS_MAX == it->second._status);  // check order status
}

int main()
{
    testCase01();

    return 0;
}

OS:          Linux
G++ Version: 4.8.2
Build CMD:   g++ -g -std=c++11  challenge.cpp -o challenge
Run      :   ./challenge

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值