public Order?DecideOrder(PositionDelta delta)
        {
            OptionQuote quote = delta.Quote ?? MarketDataClient.GetOptionQuote(delta.Symbol);

            // TODO: Remove after testing
            //Log.Warning("Not getting real quote");
            //OptionQuote quote = new OptionQuote(delta.Symbol, delta.Price * (float).99, delta.Price * (float)1.01, delta.Price, delta.Price * (float)1.06, (float)1.0);

            if (quote.Time < DateTime.Now.AddSeconds(-15))
            {
                Log.Information("Getting new quote. Old quote- {@Quote}", quote);
                quote = MarketDataClient.GetOptionQuote(delta.Symbol);
            }
            Log.Information("{DeltaType} delta {@Delta}- current mark price {Mark}. Symbol {Symbol}", delta.DeltaType, delta, quote.Mark.ToString("0.00"), delta.Symbol);

            Position?currentPos = BrokerClient.GetPosition(delta.Symbol);

            if (delta.DeltaType == DeltaType.SELL)
            {
                return(DecideSell(delta, currentPos));
            }
            else if (delta.DeltaType == DeltaType.ADD ||
                     delta.DeltaType == DeltaType.NEW)
            {
                return(DecideBuy(delta, currentPos, quote));
            }
            else
            {
                Log.Error("Unrecognized deltaType: {type}", delta.DeltaType);
                return(null);
            }
        }
        private int DecideBuyQuantity(float price, PositionDelta delta, Position?currentPos, float currentAskPrice)
        {
            IEnumerable <Order> existingBuyOrders = BrokerClient.GetOpenOrdersForSymbol(delta.Symbol)
                                                    .Where(order => order.Instruction == InstructionType.BUY_TO_OPEN);

            if (existingBuyOrders.Count() >= _config.MaxNumOpenBuyOrdersForSymbol)
            {
                Log.Warning("Many buy orders encountered: {@BuyOrders}- skipping this order.", existingBuyOrders.ToList());
                return(0);
            }
            float openBuyAlloc = AggregateBuyOrders(existingBuyOrders, currentAskPrice);

            float currentPosTotalAlloc = openBuyAlloc + (currentPos != null
                ? currentPos.LongQuantity * currentPos.AveragePrice * 100
                : 0);

            int buyQuantity;

            if (delta.DeltaType == DeltaType.NEW ||
                delta.DeltaType == DeltaType.ADD && currentPosTotalAlloc == 0)
            {
                float deltaMarketValue = delta.Price * delta.Quantity * 100;
                float percentOfMaxSize = deltaMarketValue / _config.LivePortfolioPositionMaxSize;
                if (percentOfMaxSize > 1)
                {
                    Log.Warning("New position in live portfolio exceeds expected max size. Delta {@Delta}", delta);
                    percentOfMaxSize = 1;
                }
                buyQuantity = (int)Math.Floor((percentOfMaxSize * _config.MyPositionMaxSize) / (price * 100));
            }
            else if (delta.DeltaType == DeltaType.ADD && currentPosTotalAlloc > 0)
            {
                float addAlloc = currentPosTotalAlloc * delta.Percent;
                buyQuantity = (int)Math.Floor(addAlloc / (price * 100));
            }
            else
            {
                Log.Warning("Invalid delta type supplied to DecideBuyQuantity function. Delta {@Delta}", delta);
                return(0);
            }

            float addedAlloc = buyQuantity * price * 100;
            float remainingFundsForTrading = BrokerClient.GetAvailableFundsForTrading() - addedAlloc;
            float newTotalAllocThisPos     = currentPosTotalAlloc + addedAlloc;

            if (newTotalAllocThisPos > _config.MyPositionMaxSize)
            {
                Log.Information("Buying " + buyQuantity + " {Symbol} would exceed maximum allocation of " + _config.MyPositionMaxSize.ToString("0.00"), delta.Symbol);
                return(0);
            }
            else if (remainingFundsForTrading < _config.MinAvailableFundsForTrading)
            {
                Log.Information("Buying " + buyQuantity + " {Symbol} would put available funds below " + _config.MinAvailableFundsForTrading.ToString("0.00"), delta.Symbol);
                return(0);
            }
            else
            {
                return(buyQuantity);
            }
        }
        public void ShouldManipulateDelta()
        {
            var d1 = new PositionDelta(10, 12);
            var d2 = new PositionDelta(5, 6);

            var d3 = d1 - d2;

            d3.Should().Be(d2);
        }
        /// <summary>
        /// Compares the images into the given result.
        /// </summary>
        private unsafe void CompareData(ComparisonResult result)
        {
            sampleData = null;
            masterData = BitmapUtils.LockBitmapDataRead(MasterImage);
            try
            {
                sampleData = BitmapUtils.LockBitmapDataRead(SampleImage);

                int width = MasterScanLineWidth;
                positions         = PositionDelta.ForWithinDistance(Criteria.MaxPixelDistance);
                maxSquareDistance = (255 * 255 + 255 * 255 + 255 * 255) *
                                    Criteria.MaxColorDistance;
                minSquareDistance = (255 * 255 + 255 * 255 + 255 * 255) *
                                    Criteria.MinColorDistance;

                int errorCount = 0;
                for (int y = 0; y < MasterSize.Height; y++)
                {
                    PixelData *masterPixels = (PixelData *)
                                              ((byte *)masterData.Scan0.ToPointer() + y * width);
                    PixelData *samplePixels = (PixelData *)
                                              ((byte *)sampleData.Scan0.ToPointer() + y * width);
                    for (int x = 0; x < MasterSize.Width; x++)
                    {
                        bool match = PixelsEqual(*masterPixels, *samplePixels);
                        if (!match || minSquareDistance != 0)
                        {
                            result.SetIdentical(false);
                            CheckPixel(x, y, result, ref errorCount);
                            if (errorCount > MaxErrorCount)
                            {
                                result.SetCriteriaMet(false);
                                return;
                            }
                        }
                        masterPixels++;
                        samplePixels++;
                    }
                }
            }
            finally
            {
                MasterImage.UnlockBits(masterData);
                if (sampleData != null)
                {
                    SampleImage.UnlockBits(sampleData);
                }
                masterData = null;
                sampleData = null;
            }
        }
            /// <summary>
            /// Calculates the array of positions that lie at
            /// exactly distance pixels (with grid movements).
            /// </summary>
            /// <param name="distance">Distance to get positions for.</param>
            /// <returns>An array of position deltas from a center.</returns>
            internal static PositionDelta[] ForExactDistance(int distance)
            {
                // Get the easy calculations out of our way first.
                if (distance == 0)
                {
                    return(new PositionDelta[] { new PositionDelta(0, 0) });
                }

                if (distance == 1)
                {
                    return(new PositionDelta[] {
                        new PositionDelta(0, 1),
                        new PositionDelta(1, 0),
                        new PositionDelta(0, -1),
                        new PositionDelta(-1, 0)
                    });
                }

                //
                // Do the real calculation. This is what the distance
                // grid look like:
                //
                // 4 3 2 3 4
                // 3 2 1 2 3
                // 2 1 X 1 2
                // 3 2 1 2 3
                // 4 3 2 3 4
                //
                // Basically, the exact distance is a diamong around
                // the center pixel.
                //
                PositionDelta[] result = new PositionDelta[distance * 4];

                // Fill the "upper" part of the diamond.
                int index = 0;

                for (int x = -distance; x <= distance; x++)
                {
                    result[index] = new PositionDelta(x, distance - x);
                    index++;
                }

                // Fill the "lower" part of the diamond.
                for (int x = (-distance + 1); x <= (distance - 1); x++)
                {
                    result[index] = new PositionDelta(x, x - distance);
                    index++;
                }

                return(result);
            }
            /// <summary>
            /// Calculates the array of positions that lie within
            /// distance pixels (with grid movements).
            /// </summary>
            /// <param name="distance">Distance to get positions for.</param>
            /// <returns>An array of position deltas from a center.</returns>
            internal static PositionDelta[] ForWithinDistance(int distance)
            {
                PositionDelta[] result =
                    new PositionDelta[distance * 4 * distance + 1];
                int index = 0;

                for (int i = 0; i <= distance; i++)
                {
                    PositionDelta[] part = ForExactDistance(i);
                    Array.Copy(part, 0, result, index, part.Length);
                    index += part.Length;
                }
                return(result);
            }
        public static (LightMap FloorLight, LightMap CeilingLight) Trace(
            Size dimensions,
            Func <Position, bool> isPositionObscured,
            LightRange lightRange,
            IEnumerable <LightDefinition> lights)
        {
            var floorLight   = new LightMap(lightRange, dimensions).Blackout();
            var ceilingLight = new LightMap(lightRange, dimensions).Blackout();

            foreach (var light in lights)
            {
                // Check a big square around the light. This is very brute force but it doesn't appear to cause any
                // problems.
                for (int y = 0; y < light.LengthAffected; y++)
                {
                    for (int x = 0; x < light.LengthAffected; x++)
                    {
                        var delta = new PositionDelta(x, y) - light.Radius;

                        var location = light.Center + delta;

                        if (!dimensions.Contains(location))
                        {
                            continue;
                        }

                        // check for line of sight
                        var obscured =
                            DrawingUtil.BresenhamLine(
                                start: light.Center,
                                end: location)
                            .Any(isPositionObscured);

                        if (!obscured)
                        {
                            var(floorIncrement, ceilingIncrement) = light.GetBrightness(location);

                            floorLight.Lighten(location, floorIncrement);
                            ceilingLight.Lighten(location, ceilingIncrement);
                        }
                    }
                }
            }

            return(floorLight, ceilingLight);
        }
        private Order?DecideSell(PositionDelta delta, Position?currentPos)
        {
            if (currentPos == null)
            {
                Log.Information("No current position corresponding to delta {@Delta}. Symbol {Symbol}", delta, delta.Symbol);
                return(null);
            }
            if (delta.Age.TotalMinutes > _config.MinutesUntilWarnOldSellOrder)
            {
                Log.Warning("Sell delta OLD after {Minutes} minutes for delta {@Delta}. Symbol {Symbol}", delta.Age.TotalMinutes.ToString("0"), delta, delta.Symbol);
            }
            int quantity = (int)Math.Ceiling(delta.Percent * currentPos.LongQuantity);

            Order order = new Order(delta.Symbol, quantity, InstructionType.SELL_TO_CLOSE, OrderType.MARKET, -1);

            Log.Information("Decided sell order {@Order} for Symbol {Symbol}", order, order.Symbol);
            return(order);
        }
        /// <summary>
        /// Checks whether a pixel has an acceptable neighbouring value.
        /// </summary>
        private unsafe void CheckPixel(int x, int y,
                                       ComparisonResult result, ref int errorCount)
        {
            //
            // Locals used to mark whether we're below or above range.
            // If both, below wins arbitrarily.
            //
            float belowDistance = 0;
            float aboveDistance = 0;
            bool  belowFound    = false;
            bool  aboveFound    = false;

            PixelData *masterPixel = GetPixelDataAt(
                masterData, x, y, MasterScanLineWidth);

            for (int i = 0; i < positions.Length; i++)
            {
                PositionDelta d       = positions[i];
                int           sampleX = x + d.X;
                int           sampleY = y + d.Y;
                if (sampleX < 0 || sampleX > SampleSize.Width)
                {
                    continue;
                }
                if (sampleY < 0 || sampleY > SampleSize.Height)
                {
                    continue;
                }

                PixelData *samplePixel = GetPixelDataAt(
                    sampleData, sampleX, sampleY, SampleScanLineWidth);

                float distance = ColorUtils.GetSquareLinearDistance(
                    masterPixel, samplePixel);

                if (minSquareDistance > distance)
                {
                    aboveFound    = true;
                    aboveDistance = distance;
                }
                else if (distance > maxSquareDistance)
                {
                    belowFound    = true;
                    belowDistance = distance;
                }
                else
                {
                    // Acceptable value found.
                    return;
                }
            }

            if (aboveFound)
            {
                result.AddDifference(
                    new ColorDistanceDifference(x, y,
                                                minSquareDistance, aboveDistance,
                                                ValueComparison.AboveValue));
            }
            else
            {
                System.Diagnostics.Debug.Assert(belowFound);
                result.AddDifference(new ColorDistanceDifference(
                                         x, y, maxSquareDistance, belowDistance,
                                         ValueComparison.BelowValue));
            }
            errorCount++;
        }
 public static bool getCoordinatesWithDelta(int fieldSize, int row, int column, PositionDelta posDelta, out int nextRow, out int nextColumn)
 {
     nextRow    = row + posDelta.rowDelta;
     nextColumn = column + posDelta.columnDelta;
     return(nextRow >= 0 && nextRow < fieldSize && nextColumn >= 0 && nextColumn < fieldSize);
 }
Exemple #11
0
 protected override void InsertDelta(PositionDelta delta)
 {
     _db.GetCollection <PositionDelta>().Insert(delta);
 }
        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);
        }
 public void InsertDeltaAndUpsertUsedUnderlyingSymbol(PositionDelta delta)
 {
     InsertDelta(delta);
     UpsertUsedUnderlyingSymbol(new UsedUnderlyingSymbol(delta.Symbol, delta.Time));
 }
 protected abstract void InsertDelta(PositionDelta delta);
        public TimeSortedCollection <PositionDelta> ComputeDeltasAndUpdateTables(IEnumerable <Position> livePositions, Dictionary <string, FilledOrder> symbolToRecentOrderDict)
        {
            IList <PositionDelta>  deltas       = new List <PositionDelta>();
            IEnumerable <Position> oldPositions = GetStoredPositions();

            foreach (Position livePos in livePositions)
            {
                Position?oldPos = oldPositions.Where(pos => pos.Symbol == livePos.Symbol).FirstOrDefault();
                if (oldPos == null)
                {
                    FilledOrder?  recentOrder = symbolToRecentOrderDict.GetValueOrDefault(livePos.Symbol);
                    PositionDelta delta       = new PositionDelta(
                        DeltaType.NEW,
                        livePos.Symbol,
                        livePos.LongQuantity,
                        livePos.AveragePrice,
                        0,
                        recentOrder?.Quote,
                        recentOrder?.Time);
                    deltas.Add(delta);
                }
            }
            foreach (Position oldPos in oldPositions)
            {
                PositionDelta?delta       = null;
                Position?     livePos     = livePositions.Where(pos => pos.Symbol == oldPos.Symbol).FirstOrDefault();
                FilledOrder?  recentOrder = symbolToRecentOrderDict.GetValueOrDefault(oldPos.Symbol);
                if (livePos == null)
                {
                    delta = new PositionDelta(
                        DeltaType.SELL,
                        oldPos.Symbol,
                        oldPos.LongQuantity,
                        0, // Sell price is unknown (even if we have a recent order, since the recent order may not be exact sell order. It is simply the most recent order for that symbol.)
                        1,
                        recentOrder?.Quote,
                        recentOrder?.Time);
                }
                else if (livePos.LongQuantity > oldPos.LongQuantity)
                {
                    float deltaContracts = livePos.LongQuantity - oldPos.LongQuantity;
                    float addPrice       = (livePos.AveragePrice * livePos.LongQuantity - oldPos.AveragePrice * oldPos.LongQuantity) / deltaContracts;
                    delta = new PositionDelta(
                        DeltaType.ADD,
                        oldPos.Symbol,
                        deltaContracts,
                        addPrice,
                        deltaContracts / oldPos.LongQuantity,
                        recentOrder?.Quote,
                        recentOrder?.Time);
                }
                else if (livePos.LongQuantity < oldPos.LongQuantity)
                {
                    float deltaContracts = oldPos.LongQuantity - livePos.LongQuantity;
                    delta = new PositionDelta(
                        DeltaType.SELL,
                        oldPos.Symbol,
                        deltaContracts,
                        0, // Sell price is unknown
                        deltaContracts / oldPos.LongQuantity,
                        recentOrder?.Quote,
                        recentOrder?.Time);
                }

                if (delta != null)
                {
                    deltas.Add(delta);
                    InsertDeltaAndUpsertUsedUnderlyingSymbol(delta);

                    FilledOrder?order = symbolToRecentOrderDict.GetValueOrDefault(delta.Symbol);
                    if (order == null)
                    {
                        Log.Warning("Encountered delta without a recent order for this symbol {Symbol}. Delta {@Delta}", delta.Symbol, delta);
                    }
                }
            }
            UpdateAllPositions(livePositions);

            return(new TimeSortedCollection <PositionDelta>(deltas));
        }
        private Order?DecideBuy(PositionDelta delta, Position?currentPos, OptionQuote quote)
        {
            if (delta.DeltaType == DeltaType.ADD && currentPos == null)
            {
                Log.Information("No current position corresponding to {DeltaType} delta {@Delta}. Symbol {Symbol}", delta.DeltaType, delta, delta.Symbol);
            }
            else if (delta.DeltaType == DeltaType.NEW && currentPos != null)
            {
                Log.Warning("Current position exists {@CurrentPosition} for {DeltaType} delta {@Delta}. Taking no action for Symbol {Symbol}", currentPos, delta.DeltaType, delta, delta.Symbol);
                return(null);
            }

            if (delta.Age.TotalMinutes > _config.MinutesUntilBuyOrderExpires)
            {
                Log.Warning("New/Add delta expired after {Minutes} minutes for delta {@Delta}. Symbol {Symbol}", delta.Age.TotalMinutes.ToString("0"), delta, delta.Symbol);
                return(null);
            }

            if (delta.Price > _config.MaxBuyPrice)
            {
                Log.Information("Buy price higher than buy max limit. Skipping order. Symbol {Symbol}, Price={Price}", delta.Symbol, delta.Price);
                return(null);
            }

            float diff                = quote.Mark - delta.Price;
            float absPercent          = Math.Abs(diff / delta.Price);
            bool  withinHighThreshold = Math.Sign(diff) >= 0 && absPercent <= _config.HighBuyThreshold;
            bool  withinLowThreshold  = Math.Sign(diff) <= 0 && absPercent <= _config.LowBuyThreshold;

            int    quantity;
            string orderType;
            float  limit = -1;

            if (withinHighThreshold && _config.HighBuyStrategy == BuyStrategyType.MARKET ||
                withinLowThreshold && _config.LowBuyStrategy == BuyStrategyType.MARKET)
            {
                orderType = OrderType.MARKET;
                quantity  = DecideBuyQuantity(quote.AskPrice, delta, currentPos, quote.AskPrice); // Assume we will pay the ask price
            }
            else if (withinHighThreshold && _config.HighBuyStrategy == BuyStrategyType.DELTA_LIMIT ||
                     withinLowThreshold && _config.LowBuyStrategy == BuyStrategyType.DELTA_LIMIT)
            {
                orderType = OrderType.LIMIT;
                limit     = delta.Price;
                quantity  = DecideBuyQuantity(limit, delta, currentPos, quote.AskPrice);
            }
            else if (withinHighThreshold && _config.HighBuyStrategy == BuyStrategyType.THRESHOLD_LIMIT)
            {
                orderType = OrderType.LIMIT;
                limit     = delta.Price * (1 + _config.HighBuyLimit);
                quantity  = DecideBuyQuantity(limit, delta, currentPos, quote.AskPrice);
            }
            else if (withinLowThreshold && _config.LowBuyStrategy == BuyStrategyType.THRESHOLD_LIMIT)
            {
                orderType = OrderType.LIMIT;
                limit     = delta.Price * (1 - _config.LowBuyLimit);
                quantity  = DecideBuyQuantity(limit, delta, currentPos, quote.AskPrice);
            }
            else
            {
                Log.Information("Current mark price not within buy threshold. Skipping order. Symbol {Symbol}, Mark={Mark}", delta.Symbol, quote.Mark.ToString("0.00"));
                return(null);
            }

            if (quantity == 0)
            {
                Log.Information("Decided buy quantity of 0. Skipping Order. Symbol {Symbol}, CurrentPosition = {@CurrentPosition}, Delta = {@Delta}",
                                delta.Symbol, currentPos, delta);
                return(null);
            }
            else
            {
                DateTime cancelTime = delta.Time.Date.Equals(DateTime.Today)
                    ? delta.Time.AddMinutes(_config.MinutesUntilBuyOrderExpires)
                    : DateTime.Now.AddMinutes(_config.MinutesUntilBuyOrderExpires);

                Order order = new Order(delta.Symbol, quantity, InstructionType.BUY_TO_OPEN, orderType, limit, cancelTime);
                Log.Information("Decided new Order: {@Order} for Symbol {Symbol}", order, order.Symbol);
                return(order);
            }
        }