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); }
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); } }