def onBars(self, broker_, bars): self.__volumeUsed = {} self.__volumeLeft = {} # Reset volumes. for bar in bars.getBars(): instrument = bar.getInstrument() self.__volumeUsed[instrument] = 0.0 if self.__volumeLimit is not None: # For TRADE bars we can use all the volume available. if bar.getFrequency() == pyalgotrade.bar.Frequency.TRADE: volumeLeft = bar.getVolume() else: volumeLeft = self.__instrumentTraits.round( bar.getVolume() * self.__volumeLimit, bar.getInstrument().symbol, roundDown=True) self.__volumeLeft[instrument] = volumeLeft
def fillStopOrder(self, broker_, order, bar): assert bar.getInstrument() == order.getInstrument() ret = None # First check if the stop price was hit so the market order becomes active. stopPriceTrigger = None if not order.getStopHit(): stopPriceTrigger = get_stop_price_trigger( order.getAction(), order.getStopPrice(), broker_.getUseAdjustedValues(), bar) order.setStopHit(stopPriceTrigger is not None) # If the stop price was hit, check if we can fill the market order. if order.getStopHit(): # Calculate the fill size for the order. fillSize = self.__calculateFillSize(broker_, order, bar) if fillSize == 0: broker_.getLogger().debug( "Not enough volume to fill %s stop order [%s] for %s share/s" % (order.getInstrument(), order.getId(), order.getRemaining())) return None # If we just hit the stop price we'll use it as the fill price. # For the remaining bars we'll use the open price. if stopPriceTrigger is not None: price = stopPriceTrigger else: price = bar.getOpen(broker_.getUseAdjustedValues()) assert price is not None # Don't slip prices when the bar represents the trading activity of a single trade. if bar.getFrequency() != pyalgotrade.bar.Frequency.TRADE: price = self.__slippageModel.calculatePrice( order, price, fillSize, bar, self.__volumeUsed[bar.getInstrument()]) ret = FillInfo(price, fillSize) return ret
def fillMarketOrder(self, broker_, order, bar): assert bar.getInstrument() == order.getInstrument() # Calculate the fill size for the order. fillSize = self.__calculateFillSize(broker_, order, bar) if fillSize == 0: broker_.getLogger().debug( "Not enough volume to fill %s market order [%s] for %s share/s" % (order.getInstrument(), order.getId(), order.getRemaining())) return None # Unless its a fill-on-close order, use the open price. if order.getFillOnClose(): price = bar.getClose(broker_.getUseAdjustedValues()) else: price = bar.getOpen(broker_.getUseAdjustedValues()) assert price is not None # Don't slip prices when the bar represents the trading activity of a single trade. if bar.getFrequency() != pyalgotrade.bar.Frequency.TRADE: price = self.__slippageModel.calculatePrice( order, price, fillSize, bar, self.__volumeUsed[bar.getInstrument()]) return FillInfo(price, fillSize)
def __calculateFillSize(self, broker_, order, bar): ret = 0 # If self.__volumeLimit is None then allow all the order to get filled. if self.__volumeLimit is not None: maxVolume = self.__instrumentTraits.round( self.__volumeLeft.get(bar.getInstrument(), 0), order.getInstrument().symbol) else: maxVolume = order.getRemaining() if not order.getAllOrNone(): ret = min(maxVolume, order.getRemaining()) elif order.getRemaining() <= maxVolume: ret = order.getRemaining() return ret
def fillLimitOrder(self, broker_, order, bar): assert bar.getInstrument() == order.getInstrument() # Calculate the fill size for the order. fillSize = self.__calculateFillSize(broker_, order, bar) if fillSize == 0: broker_.getLogger().debug( "Not enough volume to fill %s limit order [%s] for %s share/s" % (order.getInstrument(), order.getId(), order.getRemaining())) return None ret = None price = get_limit_price_trigger(order.getAction(), order.getLimitPrice(), broker_.getUseAdjustedValues(), bar) if price is not None: ret = FillInfo(price, fillSize) return ret
def fillStopLimitOrder(self, broker_, order, bar): assert bar.getInstrument() == order.getInstrument() ret = None # First check if the stop price was hit so the limit order becomes active. stopPriceTrigger = None if not order.getStopHit(): stopPriceTrigger = get_stop_price_trigger( order.getAction(), order.getStopPrice(), broker_.getUseAdjustedValues(), bar) order.setStopHit(stopPriceTrigger is not None) # If the stop price was hit, check if we can fill the limit order. if order.getStopHit(): # Calculate the fill size for the order. fillSize = self.__calculateFillSize(broker_, order, bar) if fillSize == 0: broker_.getLogger().debug( "Not enough volume to fill %s stop limit order [%s] for %s share/s" % (order.getInstrument(), order.getId(), order.getRemaining())) return None price = get_limit_price_trigger(order.getAction(), order.getLimitPrice(), broker_.getUseAdjustedValues(), bar) if price is not None: # If we just hit the stop price, we need to make additional checks. if stopPriceTrigger is not None: if order.isBuy(): # If the stop price triggered is lower than the limit price, then use that one. # Else use the limit price. price = min(stopPriceTrigger, order.getLimitPrice()) else: # If the stop price triggered is greater than the limit price, then use that one. # Else use the limit price. price = max(stopPriceTrigger, order.getLimitPrice()) ret = FillInfo(price, fillSize) return ret