public TransactionFee EstimateTransactionFee(ExchangeOrderType orderType, decimal orderAmount, Currency orderAmountCurrency, ExchangeTradePair tradePair) { #warning watch out ... this was copied and pasted // Check what's the preferred currency (BTC) and take 0.25% of it. var fee = (orderAmountCurrency == SystemSetting.PreferredCyptoCurrency ? 1.0m : tradePair.LatestPrice) * orderAmount * tradePair.FeePercent / 100m; return(new TransactionFee() { Amount = fee, Currency = SystemSetting.PreferredCyptoCurrency }); }
/// <summary> /// If we have a trade pair of for instance ETH - BTC then to exhange x-ETH to y-BTC we're doing a sell order. /// In other words the from currency is the one that dictates. /// </summary> public ExchangeOrderAction(ExchangeTradePair tradePair, ExchangeOrderType orderType, decimal txAmountInPreferredCurrency, Currency txCurrency) { this.TradePair = tradePair; this.OrderType = orderType; this.BaseCurrency = txCurrency; // The base currency is the to currency this.EstimatedCost = this.TradePair.FeePercent / 100m * txAmountInPreferredCurrency; this.MaxExposureCost = 0m; // We set this to zero as order actions are instantaneous. this.EstimatedTimeToExecute = new TimeSpan(0, 0, 10); // We arbitrarly set the estimated time to execute to 10seconds. Generally, buying or selling at market price will be executed immediately. this.TradingIntegration = tradePair.Exchange.TradingIntegration; // It's good to assume that if this point is reached then the exchange trading was integrated. this.TransactionAmount = txAmountInPreferredCurrency; // In a trade pair of ETH -> BTC we always consider the from as the ETH this.FromAccount = this.TradePair.Exchange.TradeAccounts.Where(x => x.Currency == this.TradePair.TradePair.FromCurrency).Single(); this.ToAccount = this.TradePair.Exchange.TradeAccounts.Where(x => x.Currency == this.TradePair.TradePair.ToCurrency).Single(); }
public ExchangeOrder(ExchangeOrder order, BigInteger newPrice, BigInteger newOrderSize) { Uid = order.Uid; Timestamp = order.Timestamp; Creator = order.Creator; Amount = newOrderSize; BaseSymbol = order.BaseSymbol; Price = newOrderSize; QuoteSymbol = order.QuoteSymbol; Side = order.Side; Type = order.Type; }
public ExchangeOrder(BigInteger uid, Timestamp timestamp, Address creator, BigInteger amount, string baseSymbol, BigInteger price, string quoteSymbol, ExchangeOrderSide side, ExchangeOrderType type) { Uid = uid; Timestamp = timestamp; Creator = creator; Amount = amount; BaseSymbol = baseSymbol; Price = price; QuoteSymbol = quoteSymbol; Side = side; Type = type; }
protected OrderEventArgs(DateTime timeStamp, ClientOrderId clientOrderId, Instrument instrument, ExchangeOrderType orderType, Side side, decimal?price, decimal workingSize) { TimeStamp = timeStamp; ClientOrderId = clientOrderId; Instrument = instrument; OrderType = orderType; Side = side; Price = price; WorkingSize = workingSize; }
public ExchangeOrderCancelledEventArgs(DateTime timeStamp, ClientOrderId clientOrderId, Instrument instrument, ExchangeOrderType orderType, Side side, decimal?price, decimal workingSize) : base(timeStamp, clientOrderId, instrument, orderType, side, price, workingSize) { }
public ExchangeOrderRejectedEventArgs(DateTime timeStamp, ClientOrderId clientOrderId, Instrument instrument, ExchangeOrderType orderType, Side side, decimal?price, decimal size, string rejectReason) : base(timeStamp, clientOrderId, instrument, orderType, side, price, size) { RejectReason = rejectReason; }
public ExchangeOrderFilledEventArgs(DateTime timeStamp, ClientOrderId clientOrderId, Instrument instrument, ExchangeOrderType exchangeOrderType, Side side, decimal?price, decimal workingSize, decimal filledSize) : base(timeStamp, clientOrderId, instrument, exchangeOrderType, side, price, workingSize) { FilledSize = filledSize; }
public ExchangeOrderAcknowledgedEventArgs(DateTime timeStamp, ExchangeOrderId exchangeOrderId, ClientOrderId clientOrderId, Instrument instrument, ExchangeOrderType exchangeOrderType, Side side, decimal?price, decimal workingSize) : base(timeStamp, clientOrderId, instrument, exchangeOrderType, side, price, workingSize) { ExchangeOrderId = exchangeOrderId; }
public ExchangeOrder(IOrderManager orderManager, ExchangeOrderType orderType, Instrument instrument, Side side) { _self = Self; _orderManager = orderManager; _orderManager.ExchangeOrderAcknowledged += ForwardEvent; _orderManager.ExchangeOrderCancelled += ForwardEvent; _orderManager.ExchangeOrderFilled += ForwardEvent; _orderManager.ExchangeOrderRejected += ForwardEvent; OrderType = orderType; Instrument = instrument; Side = side; Become(StateNotInMarket); }
public static Task <JObject> SendOrder( this RestClient client, ClientOrderId clientOrderId, Instrument instrument, Side side, ExchangeOrderType orderType, decimal?price, decimal size, bool postOnly = true ) { // TODO: Add Time-in-Force var jobj = new JObject(); dynamic o = jobj; o.client_oid = clientOrderId.Id; o.product_id = instrument.Symbol; o.type = orderType.ToString().ToLowerInvariant(); o.side = side.ToString().ToLowerInvariant(); o.size = size; switch (orderType) { case ExchangeOrderType.Limit: o.stp = "cn"; // Self trading prevention -> cancel newest o.post_only = postOnly; goto case ExchangeOrderType.Stop; case ExchangeOrderType.Stop: o.price = price; break; case ExchangeOrderType.Market: break; } return(DoPost(client, jobj)); }
private void OpenOrder(Address from, Address provider, string baseSymbol, string quoteSymbol, ExchangeOrderSide side, ExchangeOrderType orderType, BigInteger orderSize, BigInteger price) { Runtime.Expect(Runtime.IsWitness(from), "invalid witness"); Runtime.Expect(Runtime.GasTarget == provider, "invalid gas target"); Runtime.Expect(baseSymbol != quoteSymbol, "invalid base/quote pair"); Runtime.Expect(Runtime.TokenExists(baseSymbol), "invalid base token"); var baseToken = Runtime.GetToken(baseSymbol); Runtime.Expect(baseToken.Flags.HasFlag(TokenFlags.Fungible), "token must be fungible"); Runtime.Expect(Runtime.TokenExists(quoteSymbol), "invalid quote token"); var quoteToken = Runtime.GetToken(quoteSymbol); Runtime.Expect(quoteToken.Flags.HasFlag(TokenFlags.Fungible), "token must be fungible"); if (orderType != Market) { Runtime.Expect(orderSize >= GetMinimumTokenQuantity(baseToken), "order size is not sufficient"); Runtime.Expect(price >= GetMinimumTokenQuantity(quoteToken), "order price is not sufficient"); } var uid = Runtime.GenerateUID(); //-------------- //perform escrow for non-market orders string orderEscrowSymbol = CalculateEscrowSymbol(baseToken, quoteToken, side); IToken orderEscrowToken = orderEscrowSymbol == baseSymbol ? baseToken : quoteToken; BigInteger orderEscrowAmount; BigInteger orderEscrowUsage = 0; if (orderType == Market) { orderEscrowAmount = orderSize; Runtime.Expect(orderEscrowAmount >= GetMinimumTokenQuantity(orderEscrowToken), "market order size is not sufficient"); } else { orderEscrowAmount = CalculateEscrowAmount(orderSize, price, baseToken, quoteToken, side); } //BigInteger baseTokensUnfilled = orderSize; var balance = Runtime.GetBalance(orderEscrowSymbol, from); Runtime.Expect(balance >= orderEscrowAmount, "not enough balance"); Runtime.TransferTokens(orderEscrowSymbol, from, this.Address, orderEscrowAmount); //------------ var thisOrder = new ExchangeOrder(); StorageList orderList; BigInteger orderIndex = 0; thisOrder = new ExchangeOrder(uid, Runtime.Time, from, provider, orderSize, baseSymbol, price, quoteSymbol, side, orderType); Runtime.Notify(EventKind.OrderCreated, from, uid); var key = BuildOrderKey(side, quoteSymbol, baseSymbol); orderList = _orders.Get <string, StorageList>(key); orderIndex = orderList.Add <ExchangeOrder>(thisOrder); _orderMap.Set <BigInteger, string>(uid, key); var makerSide = side == Buy ? Sell : Buy; var makerKey = BuildOrderKey(makerSide, quoteSymbol, baseSymbol); var makerOrders = _orders.Get <string, StorageList>(makerKey); do { int bestIndex = -1; BigInteger bestPrice = 0; Timestamp bestPriceTimestamp = 0; ExchangeOrder takerOrder = thisOrder; var makerOrdersCount = makerOrders.Count(); for (int i = 0; i < makerOrdersCount; i++) { var makerOrder = makerOrders.Get <ExchangeOrder>(i); if (side == Buy) { if (makerOrder.Price > takerOrder.Price && orderType != Market) // too expensive, we wont buy at this price { continue; } if (bestIndex == -1 || makerOrder.Price < bestPrice || (makerOrder.Price == bestPrice && makerOrder.Timestamp < bestPriceTimestamp)) { bestIndex = i; bestPrice = makerOrder.Price; bestPriceTimestamp = makerOrder.Timestamp; } } else { if (makerOrder.Price < takerOrder.Price && orderType != Market) // too cheap, we wont sell at this price { continue; } if (bestIndex == -1 || makerOrder.Price > bestPrice || (makerOrder.Price == bestPrice && makerOrder.Timestamp < bestPriceTimestamp)) { bestIndex = i; bestPrice = makerOrder.Price; bestPriceTimestamp = makerOrder.Timestamp; } } } if (bestIndex >= 0) { //since order "uid" has found a match, the creator of this order will be a taker as he will remove liquidity from the market //and the creator of the "bestIndex" order is the maker as he is providing liquidity to the taker var takerAvailableEscrow = orderEscrowAmount - orderEscrowUsage; var takerEscrowUsage = BigInteger.Zero; var takerEscrowSymbol = orderEscrowSymbol; var makerOrder = makerOrders.Get <ExchangeOrder>(bestIndex); var makerEscrow = _escrows.Get <BigInteger, BigInteger>(makerOrder.Uid); var makerEscrowUsage = BigInteger.Zero;; var makerEscrowSymbol = orderEscrowSymbol == baseSymbol ? quoteSymbol : baseSymbol; //Get fulfilled order size in base tokens //and then calculate the corresponding fulfilled order size in quote tokens if (takerEscrowSymbol == baseSymbol) { var makerEscrowBaseEquivalent = Runtime.ConvertQuoteToBase(makerEscrow, makerOrder.Price, baseToken, quoteToken); takerEscrowUsage = takerAvailableEscrow < makerEscrowBaseEquivalent ? takerAvailableEscrow : makerEscrowBaseEquivalent; makerEscrowUsage = CalculateEscrowAmount(takerEscrowUsage, makerOrder.Price, baseToken, quoteToken, Buy); } else { var takerEscrowBaseEquivalent = Runtime.ConvertQuoteToBase(takerAvailableEscrow, makerOrder.Price, baseToken, quoteToken); makerEscrowUsage = makerEscrow < takerEscrowBaseEquivalent ? makerEscrow : takerEscrowBaseEquivalent; takerEscrowUsage = CalculateEscrowAmount(makerEscrowUsage, makerOrder.Price, baseToken, quoteToken, Buy); } Runtime.Expect(takerEscrowUsage <= takerAvailableEscrow, "Taker tried to use more escrow than available"); Runtime.Expect(makerEscrowUsage <= makerEscrow, "Maker tried to use more escrow than available"); if (takerEscrowUsage < GetMinimumSymbolQuantity(takerEscrowSymbol) || makerEscrowUsage < GetMinimumSymbolQuantity(makerEscrowSymbol)) { break; } Runtime.TransferTokens(takerEscrowSymbol, this.Address, makerOrder.Creator, takerEscrowUsage); Runtime.TransferTokens(makerEscrowSymbol, this.Address, takerOrder.Creator, makerEscrowUsage); orderEscrowUsage += takerEscrowUsage; Runtime.Notify(EventKind.OrderFilled, takerOrder.Creator, takerOrder.Uid); Runtime.Notify(EventKind.OrderFilled, makerOrder.Creator, makerOrder.Uid); if (makerEscrowUsage == makerEscrow) { makerOrders.RemoveAt <ExchangeOrder>(bestIndex); _orderMap.Remove(makerOrder.Uid); Runtime.Expect(_escrows.ContainsKey(makerOrder.Uid), "An orderbook entry must have registered escrow"); _escrows.Remove(makerOrder.Uid); Runtime.Notify(EventKind.OrderClosed, makerOrder.Creator, makerOrder.Uid); } else { _escrows.Set(makerOrder.Uid, makerEscrow - makerEscrowUsage); } } else { break; } } while (orderEscrowUsage < orderEscrowAmount); var leftoverEscrow = orderEscrowAmount - orderEscrowUsage; if (leftoverEscrow == 0 || orderType != Limit) { orderList.RemoveAt <ExchangeOrder>(orderIndex); _orderMap.Remove(thisOrder.Uid); _escrows.Remove(thisOrder.Uid); if (leftoverEscrow > 0) { Runtime.TransferTokens(orderEscrowSymbol, this.Address, thisOrder.Creator, leftoverEscrow); Runtime.Notify(EventKind.OrderCancelled, thisOrder.Creator, thisOrder.Uid); } else { Runtime.Notify(EventKind.OrderClosed, thisOrder.Creator, thisOrder.Uid); } } else { _escrows.Set(uid, leftoverEscrow); } //TODO: ADD FEES, SEND THEM TO this.Address FOR NOW }
public Task <ExchangeOrderResponse> PlaceOrder(ExchangeOrderType orderType, decimal orderAmount, Currency orderAmountCurrency, ExchangeTradePair tradePair) { throw new NotImplementedException(); }
/// <summary> /// If we have a trade pair of for instance ETH - BTC then to exhange x-ETH to y-BTC we're doing a sell order. /// In other words the from currency is the one that dictates. /// </summary> public ExchangeOrderAction(IExchangeTrader tradingIntegration, ExchangeTradePair tradePair, ExchangeOrderType orderType, decimal transactionAmountInFromCurrency) { this.TradePair = tradePair; this.OrderType = orderType; this.BaseCurrency = this.TradePair.TradePair.ToCurrency; // The base currency is the to currency this.EstimatedCost = this.TradePair.FeePercent / 100m * transactionAmountInFromCurrency; this.MaxExposureCost = 0m; // We set this to zero as order actions are instantaneous. this.EstimatedTimeToExecute = new TimeSpan(0, 0, 10); // We arbitrarly set the estimated time to execute to 10seconds. Generally, buying or selling at market price will be executed immediately. this.TradingIntegration = tradingIntegration; this.TransactionAmount = transactionAmountInFromCurrency; }