コード例 #1
0
        public NewAndUpdatedFilledOrders IdentifyNewAndUpdatedOrders(TimeSortedCollection <FilledOrder> liveOrders, double lookbackMinutes)
        {
            DateTime cutoffTime = DateTime.Now.AddMinutes(-lookbackMinutes);

            NewAndUpdatedFilledOrders          recentOrdersResult = IdentifyRecentNewAndUpdatedOrders(liveOrders, cutoffTime);
            TimeSortedCollection <FilledOrder> oldUnseenOrders    = IdentifyOldUnseenOrders(liveOrders, cutoffTime);

            TimeSortedCollection <FilledOrder> allNewOrders = new TimeSortedCollection <FilledOrder>(recentOrdersResult.NewFilledOrders);

            foreach (FilledOrder oldUnseen in oldUnseenOrders)
            {
                allNewOrders.Add(oldUnseen);
            }

            return(new NewAndUpdatedFilledOrders(allNewOrders, recentOrdersResult.UpdatedFilledOrders));
        }
コード例 #2
0
        private NewAndUpdatedFilledOrders IdentifyRecentNewAndUpdatedOrders(TimeSortedCollection <FilledOrder> liveOrders, DateTime lookAfterTime)
        {
            // After the matching process, any unmatched filled orders will be the new filled orders
            TimeSortedCollection <FilledOrder> unmatchedRecentLiveOrders = new TimeSortedCollection <FilledOrder>(
                liveOrders.Where(order => order.Time >= lookAfterTime));
            IList <UpdatedFilledOrder> updatedFilledOrders = new List <UpdatedFilledOrder>();

            // Only retrieve orders from the last "lookbackMinutes" minutes (call it X) for matching. This assumes that:
            // 1) Order times will not be updated AFTER X minutes
            // 2) It takes longer than X minutes for every visible order in the live portfolio to be pushed out of view
            TimeSortedCollection <FilledOrder> unmatchedRecentDbOrders = new TimeSortedCollection <FilledOrder>(
                GetTodaysFilledOrders().Where(order => order.Time >= lookAfterTime));

            // 1st pass: Match with exact time. DO NOT use ToList(), since it creates a copy of each of the items!
            foreach (FilledOrder dbOrder in unmatchedRecentDbOrders)
            {
                FilledOrder?match = unmatchedRecentLiveOrders.FirstOrDefault(o => dbOrder.StrictEquals(o));
                if (match != null)
                {
                    unmatchedRecentLiveOrders.Remove(match);
                    unmatchedRecentDbOrders.Remove(dbOrder);
                }
            }
            // 2nd pass: Match using closest time
            foreach (FilledOrder dbOrder in unmatchedRecentDbOrders)
            {
                FilledOrder?match = unmatchedRecentLiveOrders.Where(o => dbOrder.EqualsIgnoreTime(o) && o.Time > dbOrder.Time).FirstOrDefault();
                if (match != null)
                {
                    unmatchedRecentLiveOrders.Remove(match);
                    UpdatedFilledOrder updated = new UpdatedFilledOrder(dbOrder, match);
                    updatedFilledOrders.Add(updated);
                    Log.Information("Updated order {@OldOrder} to {@NewOrder}", dbOrder, match);
                }
                else
                {
                    PortfolioDatabaseException ex = new PortfolioDatabaseException("No live order matched to database order");
                    Log.Error(ex, "No live order matched to database order {@Order}- Symbol {Symbol}. Current live orders {@LiveOrders}", dbOrder, dbOrder.Symbol, liveOrders);
                    throw ex;
                }
            }

            TimeSortedCollection <FilledOrder> newOrders = new TimeSortedCollection <FilledOrder>(unmatchedRecentLiveOrders);

            return(new NewAndUpdatedFilledOrders(newOrders, updatedFilledOrders));
        }
コード例 #3
0
        private TimeSortedCollection <FilledOrder> IdentifyOldUnseenOrders(TimeSortedCollection <FilledOrder> liveOrders, DateTime lookBeforeTime)
        {
            TimeSortedCollection <FilledOrder> unseenOrders = new TimeSortedCollection <FilledOrder>();

            // Add any older olders that have not been seen before to the "newOrders" set.
            TimeSortedCollection <FilledOrder> oldLiveOrders = new TimeSortedCollection <FilledOrder>(
                liveOrders.Where(order => order.Time < lookBeforeTime));

            foreach (FilledOrder oldLiveOrder in oldLiveOrders.Where(o => !OrderAlreadyExists(o)))
            {
                unseenOrders.Add(oldLiveOrder);
            }
            if (oldLiveOrders.Count > 0 && unseenOrders.Contains(oldLiveOrders.First()))
            {
                Log.Warning("Oldest visible live order was found to be new. This may indicate that some orders were missed.");
            }
            return(unseenOrders);
        }
コード例 #4
0
ファイル: Worker.cs プロジェクト: KJoslyn/OptionsTradingBot
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            //TimeSortedCollection<FilledOrder> liveOrders = new TimeSortedCollection<FilledOrder>();
            //liveOrders.Add(new FilledOrder("NIO_201204C55", (float)0.5, "BUY_TO_OPEN", "LIMIT", (float)0.5, 50, new DateTime(2020, 12, 1, 12, 25, 33)));
            //liveOrders.Add(new FilledOrder("NIO_201204C60", (float)0.5, "BUY_TO_OPEN", "LIMIT", (float)0.5, 50, new DateTime(2020, 12, 1, 12, 22, 30)));
            //liveOrders.Add(new FilledOrder("NIO_201204C62", (float)0.5, "BUY_TO_OPEN", "LIMIT", (float)0.5, 50, new DateTime(2020, 12, 1, 12, 22, 30)));
            //liveOrders.Add(new FilledOrder("NIO_201204C65", (float)0.5, "BUY_TO_OPEN", "LIMIT", (float)0.5, 50, new DateTime(2020, 12, 1, 12, 30, 00)));
            //LivePortfolioClient.IdentifyNewAndUpdatedOrders(liveOrders, 260);

            //IEnumerable<Position> positions = BrokerClient.GetPositions();
            //OptionQuote quote;
            //try
            //{
            //    quote = MarketDataClient.GetOptionQuote("AAPL_201218C140");
            //    //OptionQuote quote = MarketDataClient.GetQuote("AAPL_121819C140");
            //}
            //catch (Exception ex)
            //{
            //    Log.Information(ex, "hello");
            //}
            //Order o1 = new Order("AAPL_201218C150", 1, InstructionType.SELL_TO_CLOSE, OrderType.MARKET, (float)0.08);
            //BrokerClient.PlaceOrder(o1);
            //Log.Information("Placing Order: {@Order}", o1);

            //IList<Position> positions = await ((LottoXClient)LivePortfolioClient).GetPositionsFromImage("C:/Users/Admin/WindowsServices/MarketCode/LottoXService/screenshots/portfolio-4380.png");

            //Order o1 = new Order("AAPL_201231C150", 1, InstructionType.BUY_TO_OPEN, OrderType.LIMIT, (float).03);
            //Order o2 = new Order("CMG_201231C150", 1, InstructionType.BUY_TO_OPEN, OrderType.LIMIT, (float).03);
            //BrokerClient.PlaceOrder(o1);
            //BrokerClient.PlaceOrder(o2);

            BrokerClient.CancelExistingBuyOrders("ZM_210115C550");

            Log.Information("RETURNING EARLY");
            return;

            if (!MarketDataClient.IsMarketOpenToday())
            {
                Log.Information("Market closed today");
                return;
            }
            //Log.Information("NOT LOGGING IN");
            await LivePortfolioClient.Login();

            TimeSpan marketOpenTime  = new TimeSpan(9, 30, 0);
            TimeSpan marketCloseTime = new TimeSpan(16, 0, 0);

            int invalidPortfolioStateCount = 0;
            int errorCount = 0;

            //string seedOrdersFilename = "C:/Users/Admin/WindowsServices/MarketCode/LottoXService/screenshots/orders-4173.png";
            string seedOrdersFilename = "";

            while (!stoppingToken.IsCancellationRequested)
            {
                TimeSpan now = DateTime.Now.TimeOfDay;
                if (now >= marketCloseTime)
                {
                    Log.Information("Market now closed!");
                    ElmahClient.Dispose();
                    //Log.Information("NOT BREAKING ON MARKET CLOSED");
                    break;
                }
                else if (now <= marketOpenTime)
                {
                    Log.Information("Market not open yet!");
                    // Or, wait until 9:30am
                    await Task.Delay(30 * 1000, stoppingToken);

                    continue;
                }

                try
                {
                    Task _ = ElmahClient.Heartbeats.HealthyAsync(new Guid(_elmahConfig.LogId), _elmahConfig.HeartbeatId);

                    TimeSortedCollection <PositionDelta> deltas;

                    if (seedOrdersFilename.Length > 0)
                    {
                        Log.Information("*********Seeding live orders with file " + seedOrdersFilename);
                        deltas = await LivePortfolioClient.GetLiveDeltasFromPositions(seedOrdersFilename);

                        seedOrdersFilename = "";
                    }
                    else if (errorCount > 0 ||
                             invalidPortfolioStateCount > 0)
                    {
                        Log.Information("***Getting live deltas after error");
                        deltas = await LivePortfolioClient.GetLiveDeltasFromPositions();
                    }
                    else if (await LivePortfolioClient.HaveOrdersChanged(null))
                    {
                        Log.Information("***Change in top orders detected- getting live orders");
                        deltas = await LivePortfolioClient.GetLiveDeltasFromPositions();
                    }
                    else
                    {
                        deltas = new TimeSortedCollection <PositionDelta>();
                    }

                    foreach (PositionDelta delta in deltas)
                    {
                        Order?order = OrderManager.DecideOrder(delta);
                        if (order != null)
                        {
                            if (order.Instruction == InstructionType.SELL_TO_CLOSE)
                            {
                                BrokerClient.CancelExistingBuyOrders(order.Symbol);
                            }
                            BrokerClient.PlaceOrder(order);
                        }
                    }

                    invalidPortfolioStateCount = 0;
                    errorCount = 0;
                }
                catch (InvalidPortfolioStateException)
                {
                    invalidPortfolioStateCount++;

                    if (invalidPortfolioStateCount == 2)
                    {
                        Log.Error("Portfolio found invalid {InvalidCount} times", invalidPortfolioStateCount);
                    }
                    else if (invalidPortfolioStateCount > 2)
                    {
                        Log.Fatal("Portfolio found invalid {InvalidCount} times", invalidPortfolioStateCount);
                        break;
                    }
                    await LivePortfolioClient.Login();

                    continue;
                }
                catch (PortfolioDatabaseException)
                {
                    //Assume the exception is already logged
                    break;
                }
                catch (OptionParsingException ex)
                {
                    Log.Fatal(ex, "Error parsing option symbol. Symbol {Symbol}. Terminating program.", ex.Symbol);
                    break;
                }
                catch (ArgumentException ex)
                {
                    Log.Fatal(ex, "Arument exception encountered- terminating program.");
                    break;
                }
                catch (ModelBuilderException ex)
                {
                    Log.Error(ex, "ModelBuilderException encountered");
                    errorCount++;

                    if (errorCount > 2)
                    {
                        Log.Fatal(ex, "Too many consecutive errors encountered. Terminating program. Error count = {ErrorCount}", errorCount);
                        break;
                    }
                }
                catch (Exception ex)
                {
                    errorCount++;

                    if (errorCount <= 2)
                    {
                        Log.Error(ex, "Unexpected error: count = {ErrorCount}", errorCount);
                    }
                    else if (errorCount > 2)
                    {
                        Log.Fatal(ex, "Too many consecutive errors encountered. Terminating program. Error count = {ErrorCount}", errorCount);
                        break;
                    }
                }

                await Task.Delay(15 *1000, stoppingToken);
            }

            _hostApplicationLifetime.StopApplication();
        }
コード例 #5
0
        public TimeSortedCollection <PositionDelta> ComputeDeltasAndUpdateTables(TimeSortedCollection <FilledOrder> newOrders)
        {
            TimeSortedCollection <PositionDelta> deltas = new TimeSortedCollection <PositionDelta>();

            foreach (FilledOrder order in newOrders)
            {
                Position?     oldPos = GetPosition(order.Symbol);
                PositionDelta delta;
                if (oldPos == null) // NEW
                {
                    if (order.Instruction == InstructionType.SELL_TO_CLOSE)
                    {
                        PortfolioDatabaseException ex = new PortfolioDatabaseException("No existing position corresponding to sell order");
                        Log.Fatal(ex, "No existing position corresponding to sell order {@Order}- Symbol {Symbol}", order, order.Symbol);
                        throw ex;
                    }
                    delta = new PositionDelta(
                        DeltaType.NEW,
                        order.Symbol,
                        order.Quantity,
                        order.Price,
                        0,
                        order.Quote,
                        order.Time);
                    deltas.Add(delta);

                    Position newPos = new Position(order.Symbol, order.Quantity, order.Price);
                    InsertPosition(newPos);
                }
                else if (order.Instruction == InstructionType.BUY_TO_OPEN) // ADD
                {
                    delta = new PositionDelta(
                        DeltaType.ADD,
                        order.Symbol,
                        order.Quantity,
                        order.Price,
                        order.Quantity / oldPos.LongQuantity,
                        order.Quote,
                        order.Time);
                    deltas.Add(delta);

                    DeletePosition(oldPos);

                    int      newQuantity  = (int)oldPos.LongQuantity + order.Quantity;
                    float    averagePrice = (oldPos.AveragePrice * oldPos.LongQuantity + order.Quantity * order.Price) / newQuantity;
                    Position position     = new Position(order.Symbol, newQuantity, averagePrice);
                    InsertPosition(position);
                }
                else if (order.Instruction == InstructionType.SELL_TO_CLOSE) // SELL
                {
                    delta = new PositionDelta(
                        DeltaType.SELL,
                        order.Symbol,
                        order.Quantity,
                        order.Price,
                        order.Quantity / oldPos.LongQuantity,
                        order.Quote,
                        order.Time);
                    deltas.Add(delta);

                    DeletePosition(oldPos);

                    int newQuantity = (int)oldPos.LongQuantity - order.Quantity;
                    if (newQuantity > 0)
                    {
                        Position position = new Position(order.Symbol, newQuantity, oldPos.AveragePrice);
                        InsertPosition(position);
                    }
                }
                else
                {
                    PortfolioDatabaseException ex = new PortfolioDatabaseException("Unexpected instruction type: " + order.Instruction);
                    Log.Fatal(ex, "Unexpected instruction type");
                    throw ex;
                }
                InsertOrder(order);
                InsertDeltaAndUpsertUsedUnderlyingSymbol(delta);
            }
            return(deltas);
        }
コード例 #6
0
 public IEnumerable <Order> DecideOrdersTimeSorted(TimeSortedCollection <PositionDelta> deltas)
 {
     return(deltas.Select(delta => DecideOrder(delta))
            .OfType <Order>()); // filter out nulls
 }