Expressive Bidding
Expressive Bidding Template
About These Templates
OneChronos provides a set of pre-written bidder logic and sample data for some of the most common single-security and multi-security trading strategies. These templates are meant as a starting point for producing production bidder logic, and can be customized to your needs:
NBBO ConsensusFull Template
set the limit price at specific points throughout the bid/ask spread, as a function the proportion of exchanges agreeing on NBBO.
let score = nbbo_deviation_rate(key_mkts_data, nbb_px, nbo_px);
/* set price within spread price based on scoring (btwn 0..1) */
let dynamic_px = switch (o.order.side) {
| Buy => nbb_px + (spread * score);
| Sell => nbo_px - (spread * score);
};
Ok (Bid.([place_notional(dynamic_px * qty(o))]));
Single-Stock Indifference CurveFull Template
Express a willingness to trade different quantities at different price levels, accepting a precise max cost of liquidity for different size fills.
/* Construct an action for a given price/qty tier */
let within_qty_tier = qty(o) >= const(tier.min)
&& qty(o) <= const(tier.max);
subject_to(within_qty_tier,
place_notional(tier.px * qty(o)));
Synthetic Create or RedeemFull Template
substitute N shares of an index ETF for N units of its components (redeem), or vice versa (create).
/* Compute list of index-weighted -fill- qtys */
let weighted_qtys = List.map(o =>
o.data.weighting * qty_order(o.order), arg.orders);
/* Enforce equality across weighted fill qtys */
Ok ([subject_to(all_eq(weighted_qtys),
place_orders(arg.orders))]);
Dollar Neutral BasketFull Template
Execute a basket of stocks in any dollar-neutral combination, within some tolerance (provided via FIX along with component orders).
/* Compute net notional dollars -filled- using 'qty()' function */
let net_notional = sum_map(o =>
side_coeff(o.order.side) * qty(o), arg.orders);
Ok ([subject_to(abs(net_notional) <= const(arg.bidder_data.tolerance),
place_orders(arg.orders))]);
Midpoint DiscretionFull Template
Trade different quantities at either the midpoint or at the near touch (NBB or NBO).
let nbbo_px = switch (o.order.side) {
| Buy => mkt(o.order.symbol) |> nbb;
| Sell => mkt(o.order.symbol) |> nbo;
};
let mid_px = mkt(o.order.symbol) |> mid;
Ok ([subject_to(qty(o) <= const(mid_qty),
place_notional(mid_px * qty(o))),
subject_to(const(mid_qty) < qty(o) && qty(o) <= const(nbbo_qty),
place_notional(nbbo_px * qty(o)))]);
Dynamic Percent-of-SpreadFull Template
Express willingness to trade different quantities at different percentages of spread (with 0% meaning near touch, 50% meaning midpoint, and 100% meaning far touch).
let computed_limit (tier) = switch (o.order.side) {
| Buy => nbo - (tier.pct_of_spread / 100) * (nbo - nbb);
| Sell => nbb + (tier.pct_of_spread / 100) * (nbo - nbb);
};
Ok (List.map(
tier => { subject_to(
qty(o) >= const(tier.min_qty) && qty(o) <= const(tier.max_qty),
place_notional(computed_limit(tier) * qty(o)))
},
arg.bidder_data.tiers
));
Target Portfolio CompositionFull Template
Trade components of a given basket of securities simultaneously while enforcing specific quantity ratios between securities.
let weighted_qtys = List.map(o =>
o.data.weighting * qty_order(o.order), arg.orders);
Ok ([subject_to(all_eq(weighted_qtys),
place_orders(arg.orders))]);
Net Price BasketFull Template
Buy and/or sell a mix of securities in single "unit" increments and at a net price per unit, where "unit" is a desired fill quantity ratio across securities.
let weighted_qtys = List.map(o => qty(o)/o.data.weighting, arg.orders);
Ok ([subject_to(all_eq(weighted_qtys),
place_basket(
sum_map(o => o.data.weighting * qty(o), arg.orders),
arg.bidder_data.unit_net_price,
arg.bidder_data.max_units
))
]);
Pair SpreadFull Template
Trade two securities subject to a constraint that the price spread between them is greater than some amount.
let spread = abs(mid(a) - mid(b));
Ok ([subject_to(const(spread) >= const(arg.bidder_data.spread),
place_notional(mid(a) * qty(a) + mid(b) * qty(b)))]);
Basket of substitutesFull Template
Buy or sell a basket of stocks (e.g. an industry / sector), with indifference as to symbol-wise composition of the basket.
let total_notional = sum_map(o =>
o.order.price * qty_order(o.order), arg.orders);
Ok ([subject_to(total_notional <= const(arg.bidder_data.notional_max),
place_orders(arg.orders))
]);
ETF or Components (Any Combination)Full Template
Trade either the ETF and/or its underlying components, minimizing total cost.
let etf = List.filter(o => o.data.sec_type == ETF, orders);
let components = List.filter(o => o.data.sec_type == Component, orders);
let weighted_components = List.map(o =>
qty_order(o.order) / o.data.weighting, orders);
let within_max_notional = sum_map(o =>
o.order.price * (qty(o)), etf @ components) <= const(max_notional);
Ok ([subject_to(all_eq(weighted_components) && within_max_notional,
place_orders(etf @ components))
]);
Single Stock HedgingFull Template
Given a list of securities with weightings representing the degree to which they hedge each other, execute a single trade in some combination of those securities.
let abs_weighted_qty = sum_map(o =>
abs(o.data.hedge_qty_coeff * qty(o)), orders);
let hedge_adjusted_qty = sum_map(o =>
o.data.hedge_qty_coeff * qty(o), orders);
let hedging_constraint =
abs_weighted_qty == target_hedge_ratio * hedge_adjusted_qty;
Ok ([subject_to(hedging_constraint,
place_orders(arg.orders))]);
Weighted Long/Short PairFull Template
Buy one security and sell another, ensuring that each is filled in the desired ratio (share quantity).
let weighted_qty_a = a.data.weighting * qty(a);
let weighted_qty_b = b.data.weighting * qty(b);
Ok ([subject_to(weighted_qty_a - weighted_qty_b == const(0),
place_orders([a,b]))]);
Beta Neutral ExecutionFull Template
seek a trade that is *approximately* beta-neutral, meaning that we can tolerate some deviation from exact equality.
/* proportional change in beta (net-beta divided by gross) within some tolerance */
let beta_constraint = (
/* rearrange terms as linear: -tol <= net/abs <= tol*/
arg.bidder_data.beta_tol * beta_net + beta_abs >= const(0) &&
arg.bidder_data.beta_tol * beta_net - beta_abs <= const(0)
);
Ok ([subject_to(beta_constraint, place_orders(arg.orders))]);
Dollar Neutral PairFull Template
Trade two securities such that the expected notional amount bought in one is equal to the expected notional amount sold in the other.
let net_notional = dollars_filled(a) - dollars_filled(b);
let dollar_neutral = abs(net_notional) <= const(my_tolerance);
/* Place orders if and only if apprx dollar neutral */
Ok ([subject_to(dollar_neutral,
place_orders([a,b]))]);
Try out any of these in the Auction Simulator by replacing the simulation's existing bidder logic and data type with those of a given template. Tune the runtime arguments and auction parameters to your liking, and run the auction to see results.
If you're interested in using any of these in production, please feel free to reach out to us at [email protected] to discuss how we can help.