def test_probability_to_price(): # Exact match assert probability_to_price(0.5, side=OrderSide.BUY) == Price("2.0") # Rounding match assert probability_to_price(0.499, side=OrderSide.BUY) == Price("2.02") assert probability_to_price(0.501, side=OrderSide.BUY) == Price("2.0") assert probability_to_price(0.501, side=OrderSide.SELL) == Price("1.99")
def _determine_fill_price(self, update: Dict, order: Order): if "avp" not in update: # We don't have any specifics about the fill, assume it was filled at our price return update["p"] if order.filled_qty == 0: # New fill, simply return average price return update["avp"] else: new_price = price_to_probability(str(update["avp"])) prev_price = order.avg_px if prev_price == new_price: # Matched at same price return update["avp"] else: prev_price = probability_to_price(order.avg_px) prev_size = order.filled_qty new_price = Price.from_str(str(update["avp"])) new_size = update["sm"] - prev_size total_size = prev_size + new_size price = (new_price - ((prev_price * (prev_size / total_size)))) / ( new_size / total_size ) self._log.debug( f"Calculating fill price {prev_price=} {prev_size=} {new_price=} {new_size=} == {price=}" ) return price
def order_submit_to_betfair(command: SubmitOrder, instrument: BettingInstrument, customer_ref="1"): """ Convert a SubmitOrder command into the data required by betfairlightweight """ order = command.order # type: LimitOrder return { "market_id": instrument.market_id, # Used to de-dupe orders on betfair server side "customer_ref": order.client_order_id.value, "customer_strategy_ref": customer_ref, "instructions": [ place_instruction( order_type="LIMIT", selection_id=instrument.selection_id, side=N2B_SIDE[order.side], handicap={"0.0": "0"}.get(instrument.selection_handicap, instrument.selection_handicap), limit_order=limit_order( size=float(order.quantity), price=float( probability_to_price(probability=order.price, side=order.side)), persistence_type="PERSIST", time_in_force=N2B_TIME_IN_FORCE[order.time_in_force], min_fill_size=0, ), customer_order_ref=order.client_order_id.value, ) ], }
def _probability_to_price(probability: Price, side: OrderSide): if side == OrderSide.BUY: tick_prob = BETFAIR_TICK_SCHEME.next_bid_price(value=probability) elif side == OrderSide.SELL: tick_prob = BETFAIR_TICK_SCHEME.next_ask_price(value=probability) else: raise RuntimeError(f"invalid OrderSide, was {side}") return probability_to_price(probability=tick_prob)
def order_submit_to_betfair(command: SubmitOrder, instrument: BettingInstrument): """ Convert a SubmitOrder command into the data required by betfairlightweight """ order = command.order # type Order price = determine_order_price(order) return { "market_id": instrument.market_id, # Used to de-dupe orders on betfair server side "customer_ref": command.id.value.replace("-", ""), "customer_strategy_ref": command.strategy_id.value[:15], "instructions": [ place_instruction( order_type="LIMIT", selection_id=instrument.selection_id, side=N2B_SIDE[order.side], handicap={"0.0": "0"}.get(instrument.selection_handicap, instrument.selection_handicap), limit_order=limit_order( size=float(order.quantity), price=float( probability_to_price(probability=price, side=order.side)), persistence_type="PERSIST", time_in_force=N2B_TIME_IN_FORCE[order.time_in_force], min_fill_size=0, ), # Remove the strategy name from customer_order_ref; it has a limited size and we don't control what # length the strategy might be or what characters users might append customer_order_ref=make_custom_order_ref( client_order_id=order.client_order_id, strategy_id=command.strategy_id, ), ) ], }
def order_update_to_betfair( command: UpdateOrder, venue_order_id: VenueOrderId, side: OrderSide, instrument: BettingInstrument, ): """ Convert an UpdateOrder command into the data required by betfairlightweight """ return { "market_id": instrument.market_id, "customer_ref": command.client_order_id.value, "instructions": [ replace_instruction( bet_id=venue_order_id.value, new_price=float( probability_to_price(probability=command.price, side=side)), ) ], }
def test_probability_to_price(self, raw_prob, price): # Exact match prob = self.tick_scheme.next_bid_price(raw_prob) assert probability_to_price(prob) == Price.from_str(price)