/// <summary>Attempt to make a trade on 'pair' for the given 'price' and base 'amount'</summary> private void TryFillOrder(TradePair pair, Fund fund, long order_id, ETradeType tt, EOrderType ot, Unit <decimal> amount_in, Unit <decimal> amount_out, Unit <decimal> remaining_in, out Order ord, out OrderCompleted his) { // The order can be filled immediately, filled partially, or not filled and remain as an 'Order'. // Also, exchanges use the base currency as the amount to fill, so for Q2B trades it's possible // that 'amount_in' is less than the trade asked for. var market = m_depth[pair]; // Consume orders var price_q2b = tt.PriceQ2B(amount_out / amount_in); var amount_base = tt.AmountBase(price_q2b, amount_in: remaining_in); var filled = market.Consume(pair, tt, ot, price_q2b, amount_base, out var remaining_base); // The order is partially or completely filled... Debug.Assert(Misc.EqlAmount(amount_base, filled.Sum(x => x.AmountBase) + remaining_base)); ord = remaining_base != 0 ? new Order(order_id, fund, pair, ot, tt, amount_in, amount_out, tt.AmountIn(remaining_base, price_q2b), Model.UtcNow, Model.UtcNow) : null; his = remaining_base != amount_base ? new OrderCompleted(order_id, fund, pair, tt) : null; // Add 'TradeCompleted' entries for each order book offer that was filled foreach (var fill in filled) { his.Trades.AddOrUpdate(new TradeCompleted(his.OrderId, ++m_history_id, pair, tt, fill.AmountIn(tt), fill.AmountOut(tt), Exchange.Fee * fill.AmountOut(tt), tt.CoinOut(pair), Model.UtcNow, Model.UtcNow)); } }
/// <summary>The 'In' side of the offer</summary> public Unit <decimal> AmountIn(ETradeType tt) => tt.AmountIn(AmountBase, PriceQ2B);