0

I have two classes of interest: priceLevel and orderBook.

orderBook is a global variable that holds a pointer to a dynamic array of priceLevel pointers. priceLevel is a queue data structure that holds a third class called orderElement.

I'm struggling with my order matching function. In particular, with priceLevel. Orders on the same price level are matched properly against an incoming order, but once the queue of orderElements for a given priceLevel is depleted, I am unable to continue to the next priceLevel. This is strange because incrementing/decrementing a pointer during the first half of my function works fine, but then doesn't work when applied similarly later (see below).

My Goal is to simply increment a pointer to the memory location of the exhausted priceLevel, such that I arrive at the next priceLevel

For instance,

priceLevel* plPointer;
plPointer = &OB.priceLevels[0][0]; // First price level, first orderElement
plPointer++ // Now on OB.priceLevels[1][0];

Classes

class priceLevel {              
    private:
        int price;
        int outstandingOrders{};
        orderElement* priceHead{nullptr};
        orderElement* priceTail{nullptr};

    public:      
        priceLevel(int price);             
};
class orderBook {
    public:
        priceLevel** priceLevels;
        orderBook(int price);
};

Constructors

orderBook::orderBook(int price) {
    priceLevels = new priceLevel*[MAX_OB_PRICE - MIN_OB_PRICE];
    for (int i{MAX_OB_PRICE - MIN_OB_PRICE}; i >= 0; i--) {
            priceLevels[i] = new priceLevel(price + i);
        }
}
priceLevel::priceLevel(int p) : price{p} { 
    for (int i{ORDER_COUNT}; i >= 0; i--) {   
        orderSubmitted(randomCharacterGenerator()); //Queue orderElement 
    }
}

My placeOrder function works, until it needs to move to the next priceLevel.

Function

void trader::placeOrder(char side, int quantity, int price) { 

    priceLevel* plPointer;


    if (side == 'B') {  // Buy order.                                  
        plPointer = &OB.priceLevels[0][0];

        while(plPointer->getPrice() != bestAsk) {  
            plPointer--; // WORKS HERE PERFECTLY
        }

        do {
            while(plPointer->getHead() != NULL && quantity > 0) {
                if (plPointer->getHead()->quantity <= orderSize) {
                    plPointer->getHead()->status = tradeStatus::Filled;
                    orderSize -= plPointer->getHead()->quantity;
                    plPointer->removeHead();
                } else {
                    plPointer->getHead()->status = tradeStatus::partiallyFilled;
                    plPointer->getHead()->quantity -= orderSize;
                    quantity = 0;
                }
                executionID++ // Static global variable.
            }

            if (plPointer->getHead() == NULL) {
                bestAsk++;    // Static global variable.
                plPointer++;  // BREAKS HERE!
            }

        } while (price >= bestAsk && quantity > 0);

Results

... // 10 orders per price level. Hits the tenth and dies.
[LIMIT ORDER] (B) Order submitted for 5000 contracts at 8990.
[EXECUTION] 0: Order filled against CPTGM-COXNU-TQRAN-QZLVG-VSEQW
[EXECUTION] 1: Order filled against ZAKAH-ZJEIY-XTEZG-KKWHN-JEGUJ
[EXECUTION] 2: Order filled against ZDNMK-BOMDA-ZHBYF-STVTY-ORFTJ
[EXECUTION] 3: Order filled against IJTWQ-BDJFJ-SDXXX-MJMFW-ZEFKP
[EXECUTION] 4: Order filled against FMDUA-SWOJK-UFPLC-IVQLB-JQNKO
[EXECUTION] 5: Order filled against GJUOV-ITJVT-UJKSS-DQEFY-ZIQSL
[EXECUTION] 6: Order filled against WKELY-OXFVF-MDXIV-FZLWE-TEFMC
[EXECUTION] 7: Order filled against WACJS-XYYCG-CVACG-YIMDB-GMYSR
[EXECUTION] 8: Order filled against JYIPK-PTYRF-XEEMA-YJDLG-LVVML
[EXECUTION] 9: Order filled against NSIRG-RSQAJ-RJNPI-SDNCF-XGUVC
Segmentation fault (core dumped)
  • 4
    Why are you using C-style memory management in C++ code? – SergeyA Sep 24 '19 at 14:32
  • Most of the time, a 2d array is stored in row-major form: an entire row followed by another row followed by another. Thus, you would need to increment the pointer once for each of however many items in that row to get to the next. – anonmess Sep 24 '19 at 14:34
  • @SergeyA Most trading technology is built in C. What do you suggest I do instead? I am new to C++. –  Sep 24 '19 at 14:38
  • 1
    Even if you aren't allowed to use `std::vector`/`std::string`/`std:list`, write your (minimal) own, and don't use raw memory management elsewhere. – Jarod42 Sep 24 '19 at 14:38
  • As others mentioned, in C++ you shouldn't do any manual memory management at all. Use the standard containers instead. But if you can't because this is an exercise: Why increment or decrement the pointer, when you can simply increment and decrement the indices for accessing the array? That way you can check bounds and be sure you don't accidentally access memory before or after the array. – Max Vollmer Sep 24 '19 at 14:41
  • You can even have some aliases to quickly allow to swap type, so you can check if bug happens in your containers, or in your business code. – Jarod42 Sep 24 '19 at 14:42
  • @TomerTzadok `plPointer++ // Now on OB.priceLevels[1][0];` I think your comment is not telling the truth. The next "item" is at `OB.priceLevels[0][1]`, and that is assuming you have more than one column. If it is one column, then you have probably gone out-of-bounds, since you did not put together the dynamic 2D array in a contiguous fashion. – PaulMcKenzie Sep 24 '19 at 14:45
  • Also you initialize a 1d array of pointers, but your comments and rest of the code treat it like a 2d array. It's not a 2d array. `plPointer = &OB.priceLevels[0][0];` should be `plPointer = OB.priceLevels[0];` – Max Vollmer Sep 24 '19 at 14:47
  • @Jarod42 So, use smart pointers instead? By making my own custom class, am I not implicitly using raw pointers because I'd need to use a pointer? For example, if I wanted my own array class, I'd have an int arary with constructor as such. `i_ptr = new int[size]{};` –  Sep 24 '19 at 14:48
  • 1
    Where and how do you need pointer? `std::vector` have `data()` method if you need to call C-interface for example. – Jarod42 Sep 24 '19 at 14:54
  • *Most trading technology is built in C* May be in your particular firm. As a matter of fact, I know of only one trading firm which is known for having their software done in C (and Java). Others I am familiar with use C++ (or Java, C# or other managed language). – SergeyA Sep 24 '19 at 14:55
  • @TomerTzadok -- Also, the way you created the `priceLevels` 2D array is the worst way to do this, even if you wanted to do this by hand and not use `std::vector`. What if in the middle of that loop, a call to `new[]` fails? How do you roll-back the previous calls to `new[]`, i.e. issue a `delete[]` call to each of them? In addition, all of your rows start at some location in the heap, thus is not cache-friendly. – PaulMcKenzie Sep 24 '19 at 14:55
  • @SergeyA What changes do you suggest I make? How should I restructure this? A vector of vectors? –  Sep 24 '19 at 14:56
  • @PaulMcKenzie You're right 100%. I did some debugging and they aren't contiguous so my incrementation keeps failing. Do you recommend I use a vector of vectors? I think that may be more manageable? –  Sep 24 '19 at 14:57
  • @TomerTzadok move away from manual memory management. Use standard containers (`std::vector`, `std::list`). Do not use pointers, use indexes and/or iterators as appropriate. – SergeyA Sep 24 '19 at 14:58
  • You have 10 elements, starting from 0 and hit the element at *index* 10, which is the 11th element (just count!), therefore segfault – Wolfgang Brehm Sep 24 '19 at 15:05
  • @TomerTzadok [You can try this](https://stackoverflow.com/questions/21943621/how-to-create-a-contiguous-2d-array-in-c/21944048#21944048). Disclaimer -- there is no warranty on the code -- make changes if need be. – PaulMcKenzie Sep 24 '19 at 15:16

0 Answers0