Пример #1
0
        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);
        }
Пример #3
0
        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);
            }
        }
Пример #4
0
 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.
     }
 }
Пример #5
0
        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();
        }
Пример #6
0
        // 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.");
            }
        }