Expressive Bidding
Dynamic Peg
Dynamic Peg Walkthrough
In this document:
- A walkthrough of building limit and peg orders with bidder logic
- A simple example of how bidder data introduces runtime flexibility
In this section, we'll walk through the simplest examples of bidder logic: limit and peg orders. To familiarize ourselves with bidder logic structure, we'll start out with a basic limit order without a pegged price. (Note that this limit bidder example is purely illustrative and would have the same effect as submitting a standard Limit Order)
Simple Limit Order
Buy up to 100 shares of AAPL at 140 dollars:
let limit_bidder: bidder(_) = (arg, ~mkt) => {
let aapl = List.hd(arg.orders); /* expects 1 order in the `orders` parameter */
open Bid; /* opens `Bid` module needed for return actions */
Ok ([
subject_to(qty(aapl) <= const(100),
place_notional(140 * qty(aapl)))
])
}
The above uses a hard-coded value for price (140
), making it difficult to reuse this code. By instead providing these terms through a target order (the order
argument), our bidder can be generalized to any symbol, price, and quantity. Here, we use the symbol, price, and quantity from the target order. We also make use of the place_orders
return for simplicity:
let limit_bidder: bidder(_) = (arg, ~mkt) => {
let aapl = List.hd(arg.orders); /* expects 1 order in the `orders parameter */
open Bid;
Ok ([
subject_to(qty(aapl) <= const(100),
place_orders([aapl]))
])
}
Primary Peg
Now let's make the order more interesting and peg our limit price to the market data measured by OneChronos. Suppose you want to always peg to one increment below the NBB (e.g. more aggressive than NBB for a sell order). You can use the nbb
helper function to access the NBB measured by OneChronos at the time of auction. The |>
is a "pipe" symbol, making the statement equivalent to nbb(mkt(o.order.symbol))
.
let limit_peg: bidder(_) = (arg, ~mkt) => {
let o = List.hd(arg.orders); /* expects 1 order in the `orders parameter */
let peg_price = (mkt(o.order.symbol) |> nbb) - 1;
open Bid;
Ok ([subject_to(qty(o) <= const(100),
place_notional(peg_price * qty(o))) /* place order with pegged price as new limit */
])
}
Dynamic Peg
We reference the symbol of our target order using o.order.symbol
. Each element in the arg.orders
list has an order
property that includes data from the FIX order. The properties available in this underlying order
type are described in the programming guide below.
Rather than hard-coding the 1 dollars offset from NBB, we can use bidder_data
to dynamically adjust the amount of the offset at runtime. Our JSON bidder_data
containing our abs_offset
value provided over FIX would look like:
/* JSON bidder data */
{
"abs_offset": 1
}
Allowing us to set our peg price as follows:
type data = {
abs_offset: price
};
let limit_peg: bidder(_) = (arg, ~mkt) => {
let o = List.hd(arg.orders); /* First order in the `arg.orders` input (assumes only one) */
let peg_price = mkt((NBB, o.order.symbol)) - arg.bidder_data.abs_offset;
/* [...] same as above */
};
We can add support for both buying and selling, using the side
specified in the target order to simulate a primary peg:
type data = {
abs_offset: price
};
let limit_peg_2: bidder(_) = (arg, ~mkt) => {
let o = List.hd(arg.orders);
let sym = o.order.symbol;
let pegged_price = switch (o.order.side) {
| Buy => (mkt(sym) |> nbb) + arg.bidder_data.abs_offset
| Sell => (mkt(sym) |> nbo) - arg.bidder_data.abs_offset
};
open Bid;
Ok ([place_notional(pegged_price * qty(o))]);
}
Here we've included a switch
statement to handle "buy" and "sell" target orders, changing the semantic meaning to "Buy at {offset} inside the best bid, or sell at {offset} inside the best offer."
Next Steps
1: Check the Price-Quantity Indifference Curves templates for runnable, full-featured examples of bidder logic similar to the above.
2: Try this code in a simulated auction. Load the Auction Simulator and replace the bidder logic and data type with an example of your choosing. Tune the runtime arguments and auction parameters to your liking, and run the auction to see results.