private void HandleMinuteAgg(IStreamAgg newValue) { if (_stockActions.TryGetValue(newValue.Symbol, out var actionList)) { actionList.ForEach(action => action(new StockInput { ClosingPrice = newValue.Close, Time = newValue.EndTimeUtc, StockSymbol = newValue.Symbol }) ); } }
// Determine whether our position should grow or shrink and submit orders. private async Task HandleMinuteAgg(IStreamAgg agg) { closingPrices.Add(agg.Close); if (closingPrices.Count > 20) { closingPrices.RemoveAt(0); Decimal avg = closingPrices.Average(); Decimal diff = avg - agg.Close; // If the last trade hasn't filled yet, we'd rather replace // it than have two orders open at once. if (lastTradeOpen) { // We need to wait for the cancel to process in order to avoid // having long and short orders open at the same time. Boolean res = await alpacaTradingClient.DeleteOrderAsync(lastTradeId); } // Make sure we know how much we should spend on our position. var account = await alpacaTradingClient.GetAccountAsync(); Decimal buyingPower = account.BuyingPower; Decimal equity = account.Equity; Int64 multiplier = account.Multiplier; // Check how much we currently have in this position. Int32 positionQuantity = 0; Decimal positionValue = 0; try { var currentPosition = await alpacaTradingClient.GetPositionAsync(symbol); positionQuantity = currentPosition.Quantity; positionValue = currentPosition.MarketValue; } catch (Exception) { // No position exists. This exception can be safely ignored. } if (diff <= 0) { // Price is above average: we want to short. if (positionQuantity > 0) { // There is an existing long position we need to dispose of first Console.WriteLine($"Removing {positionValue:C2} long position."); await SubmitOrder(positionQuantity, agg.Close, OrderSide.Sell); } else { // Allocate a percent of portfolio to short position Decimal portfolioShare = -1 * diff / agg.Close * scale; Decimal targetPositionValue = -1 * equity * multiplier * portfolioShare; Decimal amountToShort = targetPositionValue - positionValue; if (amountToShort < 0) { // We want to expand our existing short position. amountToShort *= -1; if (amountToShort > buyingPower) { amountToShort = buyingPower; } Int32 qty = (Int32)(amountToShort / agg.Close); Console.WriteLine($"Adding {qty * agg.Close:C2} to short position."); await SubmitOrder(qty, agg.Close, OrderSide.Sell); } else { // We want to shrink our existing short position. Int32 qty = (Int32)(amountToShort / agg.Close); if (qty > -1 * positionQuantity) { qty = -1 * positionQuantity; } Console.WriteLine($"Removing {qty * agg.Close:C2} from short position"); await SubmitOrder(qty, agg.Close, OrderSide.Buy); } } } else { // Allocate a percent of our portfolio to long position. Decimal portfolioShare = diff / agg.Close * scale; Decimal targetPositionValue = equity * multiplier * portfolioShare; Decimal amountToLong = targetPositionValue - positionValue; if (positionQuantity < 0) { // There is an existing short position we need to dispose of first Console.WriteLine($"Removing {positionValue:C2} short position."); await SubmitOrder(-positionQuantity, agg.Close, OrderSide.Buy); } else if (amountToLong > 0) { // We want to expand our existing long position. if (amountToLong > buyingPower) { amountToLong = buyingPower; } Int32 qty = (Int32)(amountToLong / agg.Close); await SubmitOrder(qty, agg.Close, OrderSide.Buy); Console.WriteLine($"Adding {qty * agg.Close:C2} to long position."); } else { // We want to shrink our existing long position. amountToLong *= -1; Int32 qty = (Int32)(amountToLong / agg.Close); if (qty > positionQuantity) { qty = positionQuantity; } await SubmitOrder(qty, agg.Close, OrderSide.Sell); Console.WriteLine($"Removing {qty * agg.Close:C2} from long position"); } } } else { Console.WriteLine("Waiting on more data."); } }
public abstract void OnDataReceived(IStreamAgg obj);
public override void OnDataReceived(IStreamAgg obj) { // Implement the strategy }
// Determine whether our position should grow or shrink and submit orders. private void HandleMinuteAgg(IStreamAgg agg) { closingPrices.Add(agg.Close); if (closingPrices.Count > 20) { closingPrices.RemoveAt(0); Decimal avg = closingPrices.Average(); Decimal diff = avg - agg.Close; // If the last trade hasn't filled yet, we'd rather replace // it than have two orders open at once. if (lastTradeOpen) { restClient.DeleteOrderAsync(lastTradeId); } // Make sure we know how much we should spend on our position. var account = restClient.GetAccountAsync().Result; Decimal buyingPower = account.BuyingPower; Decimal portfolioValue = account.PortfolioValue; // Check how much we currently have in this position. int positionQuantity = 0; Decimal positionValue = 0; try { var currentPosition = restClient.GetPositionAsync(symbol).Result; positionQuantity = currentPosition.Quantity; positionValue = currentPosition.MarketValue; } catch (Exception e) { // No position exists. This exception can be safely ignored. } if (diff <= 0) { // Above the 20 minute average - exit any existing long position. if (positionQuantity > 0) { Console.WriteLine("Setting position to zero."); SubmitOrder(positionQuantity, agg.Close, OrderSide.Sell); } else { Console.WriteLine("No position to exit."); } } else { // Allocate a percent of our portfolio to this position. Decimal portfolioShare = diff / agg.Close * scale; Decimal targetPositionValue = portfolioValue * portfolioShare; Decimal amountToAdd = targetPositionValue - positionValue; if (amountToAdd > 0) { // Buy as many shares as we can without going over amountToAdd. // Make sure we're not trying to buy more than we can. if (amountToAdd > buyingPower) { amountToAdd = buyingPower; } int qtyToBuy = (int)(amountToAdd / agg.Close); SubmitOrder(qtyToBuy, agg.Close, OrderSide.Buy); Console.WriteLine(String.Format("Adding {0:C2} to position.", qtyToBuy * agg.Close)); } else { // Sell as many shares as we can without going under amountToAdd. // Make sure we're not trying to sell more than we have. amountToAdd *= -1; int qtyToSell = (int)(amountToAdd / agg.Close); if (qtyToSell > positionQuantity) { qtyToSell = positionQuantity; } SubmitOrder(qtyToSell, agg.Close, OrderSide.Sell); Console.WriteLine(String.Format("Removing {0:C2} from position", qtyToSell * agg.Close)); } } } else { Console.WriteLine("Waiting on more data."); } }
private static void PolygonStreamingClient_MinuteAggReceived(IStreamAgg obj) { Securities[obj.Symbol].OnMinuteAggReceived?.Invoke(obj); }