public OrderCompleted(OrderCompleted rhs) : this(rhs.OrderId, rhs.Fund, rhs.Pair, rhs.TradeType) { foreach (var fill in rhs.Trades) { Trades.AddOrUpdate(new TradeCompleted(fill)); } }
public bool Equals(OrderCompleted rhs) { return (rhs != null && OrderId == rhs.OrderId && TradeType == rhs.TradeType && Pair == rhs.Pair && Trades.SequenceEqual(rhs.Trades)); }
/// <summary>Apply the implied changes to the current balance by the given order and completed order</summary> private void ApplyToBalance(Order ord, OrderCompleted his) { if (his != null) { foreach (var trade in his.Trades) { { // Debt from CoinIn var bal = m_bal[trade.CoinIn]; bal.Total -= trade.AmountIn; if (bal.Total < 0) { throw new Exception($"Total balance of {bal.Coin} is {bal.Total}"); } } { // Credit to CoinOut var bal = m_bal[trade.CoinOut]; bal.Total += trade.AmountOut; if (bal.Total < 0) { throw new Exception($"Total balance of {bal.Coin} is {bal.Total}"); } } { // Debt the commission var bal = m_bal[trade.CommissionCoin]; bal.Total -= trade.Commission; if (bal.Total < 0) { throw new Exception($"Total balance of {bal.Coin} is {bal.Total}"); } } } { // Remove the hold var bal = m_bal[his.CoinIn]; bal.Holds.Remove(his.OrderId); } } if (ord != null) { // Update the hold for the trade var bal = m_bal[ord.CoinIn]; bal.Holds[ord.OrderId] = ord.RemainingIn; if (bal.Held > bal.Total) { throw new Exception($"Held balance of {bal.Coin} exceeds total. Held {bal.Held}, Total {bal.Total}"); } } }
/// <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)); } }
public TradeCompletedCollection(OrderCompleted order) { m_order = order; m_trades = new Dictionary <long, TradeCompleted>(); }