/// <summary> /// Will return the <see cref="SecurityCache"/> instance to use for a give Symbol. /// If the provided Symbol is a custom type which has an underlying we will try to use the /// underlying SecurityCache type cache, if the underlying is not present we will keep track /// of the custom Symbol in case it is added later. /// </summary> /// <returns>The cache instance to use</returns> public SecurityCache GetSecurityCache(Symbol symbol) { var securityCache = new SecurityCache(); if (symbol.SecurityType == SecurityType.Base && symbol.HasUnderlying) { var underlyingSecurity = _securityProvider.GetSecurity(symbol.Underlying); if (underlyingSecurity != null) { // we found the underlying, lets use its data type cache SecurityCache.ShareTypeCacheInstance(underlyingSecurity.Cache, securityCache); } else { // we didn't find the underlying, lets keep track of the underlying symbol which might get added in the future. // else when it is added, we would have to go through existing Securities and find any which use it as underlying _relatedSymbols.AddOrUpdate(symbol.Underlying, id => new ConcurrentBag <Symbol> { symbol }, (id, bag) => { bag.Add(symbol); return(bag); } ); } } else { ConcurrentBag <Symbol> customSymbols; if (_relatedSymbols.TryRemove(symbol, out customSymbols)) { // if we are here it means we added a symbol which is an underlying of some existing custom symbols foreach (var customSymbol in customSymbols) { var customSecurity = _securityProvider.GetSecurity(customSymbol); if (customSecurity != null) { // we make each existing custom security cache, use the new instance data type cache // note that if any data already existed in the custom cache it will be passed SecurityCache.ShareTypeCacheInstance(securityCache, customSecurity.Cache); } } } } return(securityCache); }
private decimal GetTickerPrice(Order order) { var security = _securityProvider.GetSecurity(order.Symbol); var tickerPrice = order.Direction == OrderDirection.Buy ? security.AskPrice : security.BidPrice; if (tickerPrice == 0) { var brokerageSymbol = _symbolMapper.GetBrokerageSymbol(order.Symbol); var tickers = GetTickers(); var ticker = tickers.FirstOrDefault(t => t.Symbol == brokerageSymbol); if (ticker == null) { throw new KeyNotFoundException($"BinanceBrokerage: Unable to resolve currency conversion pair: {order.Symbol}"); } tickerPrice = ticker.Price; } return(tickerPrice); }
/// <summary> /// Places a new order and assigns a new broker ID to the order /// </summary> /// <param name="order">The order to be placed</param> /// <returns>True if the request for a new order has been placed, false otherwise</returns> public override bool PlaceOrder(Order order) { var requestParams = new Dictionary <string, string> { { "instrument", _symbolMapper.GetBrokerageSymbol(order.Symbol) }, { "units", Convert.ToInt32(order.AbsoluteQuantity).ToString() } }; PopulateOrderRequestParameters(order, requestParams); var postOrderResponse = PostOrderAsync(requestParams); if (postOrderResponse == null) { return(false); } // if market order, find fill quantity and price var marketOrderFillPrice = 0m; if (order.Type == OrderType.Market) { marketOrderFillPrice = Convert.ToDecimal(postOrderResponse.price); } var marketOrderFillQuantity = 0; if (postOrderResponse.tradeOpened != null && postOrderResponse.tradeOpened.id > 0) { if (order.Type == OrderType.Market) { marketOrderFillQuantity = postOrderResponse.tradeOpened.units; } else { order.BrokerId.Add(postOrderResponse.tradeOpened.id.ToString()); } } if (postOrderResponse.tradeReduced != null && postOrderResponse.tradeReduced.id > 0) { if (order.Type == OrderType.Market) { marketOrderFillQuantity = postOrderResponse.tradeReduced.units; } else { order.BrokerId.Add(postOrderResponse.tradeReduced.id.ToString()); } } if (postOrderResponse.orderOpened != null && postOrderResponse.orderOpened.id > 0) { if (order.Type != OrderType.Market) { order.BrokerId.Add(postOrderResponse.orderOpened.id.ToString()); } } if (postOrderResponse.tradesClosed != null && postOrderResponse.tradesClosed.Count > 0) { marketOrderFillQuantity += postOrderResponse.tradesClosed .Where(trade => order.Type == OrderType.Market) .Sum(trade => trade.units); } // send Submitted order event const int orderFee = 0; order.PriceCurrency = _securityProvider.GetSecurity(order.Symbol).SymbolProperties.QuoteCurrency; OnOrderEvent(new OrderEvent(order, DateTime.UtcNow, orderFee) { Status = OrderStatus.Submitted }); if (order.Type == OrderType.Market) { // if market order, also send Filled order event OnOrderEvent(new OrderEvent(order, DateTime.UtcNow, orderFee) { Status = OrderStatus.Filled, FillPrice = marketOrderFillPrice, FillQuantity = marketOrderFillQuantity * Math.Sign(order.Quantity) }); } return(true); }
public static decimal GetHoldingsQuantity(this ISecurityProvider provider, Symbol symbol) { var security = provider.GetSecurity(symbol); return(security == null ? 0 : security.Holdings.Quantity); }