// Notes: // - A 'Trade' is a description of a trade that *could* be placed. It is different // to an 'Order' which is live on an exchange, waiting to be filled. // - AmountIn * Price does not have to equal AmountOut, because 'Trade' is used // with the order book to calculate the best price for trading a given amount. // The price will represent the best price that covers all of the amount, not // the spot price. // - Don't implicitly change amounts/prices based on order type for the same reason. // Instead, allow any values to be set and use validate to check they're correct. // The 'EditTradeUI' should be used to modify properties and ensure correct behaviour // w.r.t to order type. // Rounding issues: // - Quantisation doesn't help, that just makes the discrepancies larger. // - Instead, maintain separate values for amount in and amount out. These imply the // price and allow control over which side of the trade gets rounded. /// <summary>Create a trade on 'pair' to convert 'amount_in' of 'coin_in' to 'amount_out'</summary> public Trade(Fund fund, TradePair pair, EOrderType order_type, ETradeType trade_type, Unit <decimal> amount_in, Unit <decimal> amount_out, Unit <decimal>?price_q2b = null, string creator = null) { // Check trade amounts and units if (amount_in < 0m._(trade_type.CoinIn(pair))) { throw new Exception("Invalid trade 'in' amount"); } if (amount_out < 0m._(trade_type.CoinOut(pair))) { throw new Exception("Invalid trade 'out' amount"); } if (amount_out != 0 && amount_in != 0 && trade_type.PriceQ2B(amount_out / amount_in) < 0m._(pair.RateUnits)) { throw new Exception("Invalid trade price"); } CreatorName = creator ?? string.Empty; Fund = fund; Pair = pair; OrderType = order_type; TradeType = trade_type; AmountIn = amount_in; AmountOut = amount_out; PriceQ2B = price_q2b != null ? price_q2b.Value : amount_out != 0 && amount_in != 0 ? TradeType.PriceQ2B(amount_out / amount_in) : SpotPriceQ2B; }
// Notes: // - A TradeCompleted is a completed single trade that is part of an OrderCompleted // - TradeCompleted doesn't really need 'pair' and 'tt' because they are duplicates // of fields in the containing OrderCompleted. However, they allow convenient conversion // to CoinIn/CoinOut etc. public TradeCompleted(long order_id, long trade_id, TradePair pair, ETradeType tt, Unit <decimal> amount_in, Unit <decimal> amount_out, Unit <decimal> commission, Coin commission_coin, DateTimeOffset created, DateTimeOffset updated) { // Check units if (amount_in <= 0m._(tt.CoinIn(pair))) { throw new Exception("Invalid 'in' amount"); } if (amount_out <= 0m._(tt.CoinOut(pair))) { throw new Exception("Invalid 'out' amount"); } if (commission < 0m._(commission_coin)) { throw new Exception("Negative commission"); } if (created < Misc.CryptoCurrencyEpoch) { throw new Exception("Invalid creation time"); } OrderId = order_id; TradeId = trade_id; Pair = pair; TradeType = tt; AmountIn = amount_in; AmountOut = amount_out; Commission = commission; CommissionCoin = commission_coin; Created = created; Updated = updated; }
/// <summary>Return the default amount to use for a trade on 'pair' (in CoinIn currency)</summary> public Unit <decimal> DefaultTradeAmount(ETradeType tt) { var coin = tt.CoinIn(this); return(coin.DefaultTradeAmount); }