public async Task GetCurrentPosition() { try { positionQuantity = 0; positionValue = 0; currentPosition = await client.GetPositionAsync(symbol); positionQuantity = currentPosition.Quantity; positionValue = currentPosition.MarketValue; //var positions = await client.ListPositionsAsync(); //if (positions.Count > 0) //{ // currentPosition = positions.FirstOrDefault(); //} //else //{ // currentPosition = new Position(); //} StatusChanged(); } catch { // currentPosition = new Position(); // No position exists. This exception can be safely ignored. } }
public async void GetPositionWorks() { var position = await _alpacaTradingClient.GetPositionAsync(Symbol); Assert.NotNull(position); Assert.Equal(Symbol, position.Symbol); }
public async Task <Trading.OrderResult> PlaceOrder_SellStopLimit( Data.Format format, string symbol, int shares, decimal stopPrice, decimal limitPrice, TimeInForce timeInForce = TimeInForce.Gtc) { IAlpacaTradingClient trading = null; try { if (format == Data.Format.Live) { if (String.IsNullOrWhiteSpace(Settings.API_Alpaca_Live_Key) || String.IsNullOrWhiteSpace(Settings.API_Alpaca_Live_Secret)) { return(Trading.OrderResult.Fail); } trading = Environments.Live.GetAlpacaTradingClient(new SecretKey(Settings.API_Alpaca_Live_Key, Settings.API_Alpaca_Live_Secret)); } else if (format == Data.Format.Paper) { if (String.IsNullOrWhiteSpace(Settings.API_Alpaca_Paper_Key) || String.IsNullOrWhiteSpace(Settings.API_Alpaca_Paper_Secret)) { return(Trading.OrderResult.Fail); } trading = Environments.Paper.GetAlpacaTradingClient(new SecretKey(Settings.API_Alpaca_Paper_Key, Settings.API_Alpaca_Paper_Secret)); } // Prevents exceptions or unwanted behavior with Alpaca API var account = await trading.GetAccountAsync(); if (trading == null || account == null || account.IsAccountBlocked || account.IsTradingBlocked || account.TradeSuspendedByUser) { return(Trading.OrderResult.Fail); } // Prevents unintentionally short selling (selling into negative digits, the API interprets that as intent to short-sell) var positions = await trading.ListPositionsAsync(); if (!positions.Any(p => p.Symbol == symbol)) // If there is no position for this symbol { return(Trading.OrderResult.Fail); } var position = await trading.GetPositionAsync(symbol); // If there were no position, this would throw an Exception! if (position == null || position.Quantity < shares) // If the current position doesn't have enough shares { return(Trading.OrderResult.Fail); } var order = await trading.PostOrderAsync(StopLimitOrder.Sell(symbol, shares, stopPrice, limitPrice).WithDuration(timeInForce)); return(Trading.OrderResult.Success); } catch (Exception ex) { await Log.Error($"{MethodBase.GetCurrentMethod().DeclaringType}: {MethodBase.GetCurrentMethod().Name}", ex); return(Trading.OrderResult.Fail); } }
private async Task ClosePositionAtMarket() { try { var positionQuantity = (await alpacaTradingClient.GetPositionAsync(symbol)).Quantity; await alpacaTradingClient.PostOrderAsync( OrderSide.Sell.Market(symbol, positionQuantity)); } catch (Exception) { // No position to exit. } }
public async Task Run() { alpacaTradingClient = Environments.Paper.GetAlpacaTradingClient(new SecretKey(API_KEY, API_SECRET)); alpacaDataClient = Environments.Paper.GetAlpacaDataClient(new SecretKey(API_KEY, API_SECRET)); // First, cancel any existing orders so they don't impact our buying power. var orders = await alpacaTradingClient.ListOrdersAsync(new ListOrdersRequest()); foreach (var order in orders) { await alpacaTradingClient.DeleteOrderAsync(order.OrderId); } // Figure out when the market will close so we can prepare to sell beforehand. var calendars = (await alpacaTradingClient .ListCalendarAsync(new CalendarRequest().SetTimeInterval(DateTime.Today.GetInclusiveIntervalFromThat()))) .ToList(); var calendarDate = calendars.First().TradingDateUtc; var closingTime = calendars.First().TradingCloseTimeUtc; closingTime = new DateTime(calendarDate.Year, calendarDate.Month, calendarDate.Day, closingTime.Hour, closingTime.Minute, closingTime.Second); Console.WriteLine("Waiting for market open..."); await AwaitMarketOpen(); Console.WriteLine("Market opened."); // Check every minute for price updates. TimeSpan timeUntilClose = closingTime - DateTime.UtcNow; while (timeUntilClose.TotalMinutes > 15) { // Cancel old order if it's not already been filled. await alpacaTradingClient.DeleteOrderAsync(lastTradeId); // Get information about current account value. var account = await alpacaTradingClient.GetAccountAsync(); Decimal buyingPower = account.BuyingPower; Decimal portfolioValue = account.Equity; // Get information about our existing 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. } var barSet = await alpacaDataClient.GetBarSetAsync( new BarSetRequest(symbol, TimeFrame.Minute) { Limit = 20 }); var bars = barSet[symbol].ToList(); Decimal avg = bars.Average(item => item.Close); Decimal currentPrice = bars.Last().Close; Decimal diff = avg - currentPrice; if (diff <= 0) { // Above the 20 minute average - exit any existing long position. if (positionQuantity > 0) { Console.WriteLine("Setting position to zero."); await SubmitOrder(positionQuantity, currentPrice, OrderSide.Sell); } else { Console.WriteLine("No position to exit."); } } else { // Allocate a percent of our portfolio to this position. Decimal portfolioShare = diff / currentPrice * 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; } Int32 qtyToBuy = (Int32)(amountToAdd / currentPrice); await SubmitOrder(qtyToBuy, currentPrice, OrderSide.Buy); } 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; Int32 qtyToSell = (Int32)(amountToAdd / currentPrice); if (qtyToSell > positionQuantity) { qtyToSell = positionQuantity; } await SubmitOrder(qtyToSell, currentPrice, OrderSide.Sell); } } // Wait another minute. Thread.Sleep(60000); timeUntilClose = closingTime - DateTime.UtcNow; } Console.WriteLine("Market nearing close; closing position."); await ClosePositionAtMarket(); }
// 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."); } }