Passing a Global into a Function and Altering it

Hello, I have a global variable of type orderBook. The class is detailed below.

1
2
3
4
5
class orderBook {
    public:
        std::vector<priceLevel> levels;  
        ... // Other functions removed for readability.     
};


I declare this global at the beginning of my CPP file.

 
orderBook OB(9000);


This class stores a vector of price levels. Each priceLevel holds a queue of orderElements, see below.

1
2
3
4
5
6
class priceLevel {              
    public:
        int price;
        std::queue<orderElement> orderQueue;
        ... // Other functions removed for readability.
};


Each orderElement is an order.

Instead of passing my orderBook (declared as OB) into the function, I take a priceLevel from the std::vector<priceLevel> levels in the orderBook by reference as such:

 
priceLevel& pricePoint = OB.levels[priceEntry]; 



I believe this is the root cause for much of my woes, as trades that are matched are not persisting.

For instance, the bestBid starts at 8975, the bestAsk starts at 8976. A user places a sell for a large amount of contracts at a price of 8974, eating through the 8975 and 8974 level. The remainder of his unmatched contracts are queued into 8974. The bestBid and bestAsk are updated to 8973 and 8974 respectively. Given that he has eaten through the 8974 level, his remaining contracts on the 8974 level should be the first to be matched from an incoming buy order.

I provide an example of the output below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[EXECUTION] 0: Order (MTAXY-DZXWE-RNWEH-DAPIO-PCGEO) fully filled at 8975 
// Execution 0 is against a sell order for 1200 contracts @ 8974 (order A).
// Order A eats through 8975
[EXECUTION] 1: Order (KIIAO-KZLUE-UDDCF-YZRJM-XLEBZ) fully filled at 8974 
// Execution 1 is against order A as well.
// Order A eats through 8974
[ORDER SUBMITTED] (QIXQG-GSLBQ-IIUKC-RSJGV-LWUUV) for 1044 contracts. 
// Order A was issued for 8974 and can't go deeper.
// Remaining unmatched contracts lie dormant on 8974. 
// These contracts should be the first to match with an incoming buy order.
[EXECUTION] 2: Order (KIIAO-KZLUE-UDDCF-YZRJM-XLEBZ) fully filled at 8974
// Incoming buy order (order B) fills against a sell order which shouldn't theoretically be there
// This was already eaten through on 8974. 
// Should have matched against QIXQG-GSLBQ-IIUKC-RSJGV-LWUUV 


My questions are:
1. Should I be passing the entire orderbook by reference, even though it's a global?
2. If I want to index into std::vector<priceLevels> levels to performing my matching operation, do I need to assign it to a new variable by reference for any operations on it to persist? Or is passing the orderbook by reference all that matters? For instance, is this needed (see below)?

1
2
3
void matchingFunction(int quantity, int price, orderBook& x) {
    priceLevel& levelofInterest = x.levels[2]
}


Thanks for reading through my long-winded question. I've been hacking at this for a while so I apologize if I'm getting things confused.
Last edited on
Why do you have a global at all?

I don't think that your issue is within the code that you have shown so far.
Passing a Global into a Function and Altering it

No need to pass a global into a function.

Being global a variable is visible everywhere.

Being global it is alterable everywhere. Even in code that shouldn't.
@keskiverto

I want it as a global so I can refer to it anywhere and at anytime, just like bestBid and bestAsk are also globals.

In my matching function, once a priceLevel in the std::vector<priceLevel> levels vector has been exhausted (is empty), I move onto the next level through

1
2
3
4
5
if (pricePoint.isEmpty()) {
        bestBid--; // Exhausted current level. Move down one.
        pricePoint = OB.levels[...]; // Find the level corresponding to the new bestBid
        matchingOrder = pricePoint.getNextOrder(); // Get the first order in the queue.
}


Maybe pricePoint here is taking a copy of the global orderbook? I'm not sure if it would take a copy, or a reference of the global orderbook, given that, on a previous iteration of my matching function, it was declared as a reference as such:
 
priceLevel& pricePoint = OB.levels[OBEntryPoint];   


Ugh...
Last edited on
I want it as a global so I can refer to it anywhere and at anytime, just like bestBid and bestAsk are also globals.

This is a really bad habit to get into. As your projects get bigger in size, you will find this makes it harder to track down problems that involve using those global variables.

It would be much better right now to get into the habit of properly limiting the scope of your variables, and passing them only to where they're needed.
I want it as a global so I can refer to it anywhere

Then there is ZERO need to pass it into ANY function as a parameter. As a copy or a pointer/reference.

Your global will be visible AND alterable in every bit of code in your source file after the global is created.
you can wrap a global in a class by making a static member. then you can, anywhere, any time, just say

classname foo;
foo.global = newvalue; //or use a setter/ getter

this protects you from many of the global problems while giving you a sort of global.
It still has risks, of course, but no more than any class with a static member would suffer -- you have to take care with anything that modifies the value, very careful..
priceLevel& pricePoint = OB.levels[priceEntry];

Once you do this, you must ensure that OB.levels doesn't get resized during the lifetime of the reference pricePoint. It might get resized if you add (or remove?) items from OB.levels. There are other methods that can do it too, such as reserve():

1
2
3
4
5
6
7
8
9
10
11
12
vector<int> myInts(10);

void foo(int &ir){
{
    myInts.push_back(1);  // myInt's data might move due to resizing
    ir = 2;   // error. ir reference is no longer valid
}

int main()
{
    foo(myInts[2]);
}


The reference becomes invalid due to the way references work. A reference binds to the address of the referenced variable. If the vector resizes, it might be forced to move the data. Since the reference refers to the old data's address, the reference becomes invalid.
Did you say that you have:
1
2
3
4
5
6
priceLevel& pricePoint = foo;

if ( pricePoint.isEmpty() )
{
   pricePoint = bar;
}


You do realise that the above is exactly same as:
1
2
3
4
if ( foo.isEmpty() )
{
   foo = bar;
}

Is it really intentional to copy all of bar into foo, or did you think that pricePoint will refer to bar after assignment?


1. You cannot change what a reference refers to.
2. Reference can nevertheless become invalid.
Last edited on
@keskiverto
I want to operate on one individual level of the global object OB at a time, which has multiple priceLevels. If a priceLevel is empty, I want it to remain empty, as it may be filled with new orders later down the road. Replacing an empty priceLevel (foo) with a full priceLevel (bar) ruins the nature of an orderbook.

I think my problem is that I'm trying to change what a reference refers to. I.e. I'm doing:
 
priceLevel& pricePoint = Foo // One level of the orderbook. 

And once this level is exhausted I set pricePoint to the nextLevel. Would it be better to use a pointer of type priceLevel?
Last edited on
no. if its a pointer into a stl container, its going to die just like an iterator, if the container reallocs under the hood. And a pure pointer solution is kinda retro, since containers are better.

can you save the index into a vector? That is the same, even if the vector is reallocated... or a key into a map, or something like this?
Last edited on
With index:
1
2
3
4
5
6
size_t index = foo;
if ( OB.levels[index].isEmpty() )
{
  index = // new bestBid
}
matchingOrder = OB.levels[index].getNextOrder();
Topic archived. No new replies allowed.