def testAlgoStopEntryOrder(self): symbol = Symbol.get('TEST') start_time = datetime.datetime(2015, 7, 7, 12) # symbol = algo.analysis_symbols()[0] ticks = [] ticks.append(Tick(start_time.timestamp(), 10.0, 10.1)) start_time = start_time + MarketDataPeriod.MIN_1 ticks.append(Tick(start_time.timestamp(), 11.0, 11.1)) start_time = start_time + MarketDataPeriod.MIN_1 ticks.append(Tick(start_time.timestamp(), 12.0, 12.1)) start_time = start_time + MarketDataPeriod.MIN_1 ticks.append(Tick(start_time.timestamp(), 12.3, 12.4)) start_time = start_time + MarketDataPeriod.MIN_1 ticks.append(Tick(start_time.timestamp(), 12.8, 12.9)) dataProvider = SimulatedDataProvider(symbol, ticks) order_manager = Broker(dataProvider) order_manager.subscribeSymbol(symbol) order = Order(symbol, 1, Entry(Entry.Type.STOP_ENTRY, 11.3), Direction.LONG) order_creator = OrderCreator(order_manager, symbol, order) order_manager.addPriceObserver(order_creator.handle_data) order_manager.start() self.assertEqual(0, len(order_manager.orders)) self.assertEqual(1, len(order_manager.positions)) self.assertEqual(State.FILLED, order.status) position = order_manager.positions[0] self.assertEqual(Position.PositionStatus.OPEN, position.status) self.assertEqual(12.1, position.entry_price)
def testAlgoExpiredOrder(self): symbol = Symbol.get('TEST') start_time = datetime.datetime(2015, 7, 7, 12) order = Order(symbol, 1, Entry(Entry.Type.STOP_ENTRY, 12.5), Direction.LONG, expire_time=datetime.timedelta(seconds=90), entry_time=start_time) # symbol = algo.analysis_symbols()[0] ticks = [] ticks.append(Tick(start_time.timestamp(), 10.0, 10.1)) start_time = start_time + MarketDataPeriod.MIN_1 ticks.append(Tick(start_time.timestamp(), 11.0, 11.1)) start_time = start_time + MarketDataPeriod.MIN_1 ticks.append(Tick(start_time.timestamp(), 12.0, 12.1)) start_time = start_time + MarketDataPeriod.MIN_1 ticks.append(Tick(start_time.timestamp(), 12.3, 12.4)) start_time = start_time + MarketDataPeriod.MIN_1 ticks.append(Tick(start_time.timestamp(), 12.8, 12.9)) dataProvider = SimulatedDataProvider(symbol, ticks) order_manager = Broker(dataProvider) order_manager.subscribeSymbol(symbol) order_creator = OrderCreator(order_manager, symbol, order) order_manager.addPriceObserver(order_creator.handle_data) order_manager.start() self.assertEqual(0, len(order_manager.orders)) self.assertEqual(0, len(order_manager.positions)) self.assertEqual(State.EXPIRED, order.status)
def testTakeProfitMarketOrder(self): symbol = Symbol.get('TEST') symbol.lot_size = 1 start_time = datetime.datetime(2015, 7, 7, 12) # symbol = algo.analysis_symbols()[0] ticks = [] ticks.append(Tick(start_time.timestamp(), 10.0, 10.1)) start_time = start_time + MarketDataPeriod.MIN_1 ticks.append(Tick(start_time.timestamp(), 11.0, 11.1)) start_time = start_time + MarketDataPeriod.MIN_1 ticks.append(Tick(start_time.timestamp(), 13.0, 13.1)) dataProvider = SimulatedDataProvider(symbol, ticks) order_manager = Broker(dataProvider) order_manager.subscribeSymbol(symbol) order = Order(symbol, 1, Entry(Entry.Type.MARKET), Direction.LONG, take_profit=2) order_creator = OrderCreator(order_manager, symbol, order) order_manager.addPriceObserver(order_creator.handle_data) order_manager.addPositionObserver(lambda position, state: self.setPosition(position)) order_manager.start() self.assertEqual(0, len(order_manager.orders)) self.assertEqual(0, len(order_manager.positions)) self.assertEqual(State.FILLED, order.status) self.assertIsNotNone(self.position) self.assertEqual(Position.PositionStatus.TAKE_PROFIT, self.position.status) self.assertEqual(12.1, self.position.exit_price) self.assertAlmostEquals(2.0, self.position.points_delta())
def evaluate_quote_update(self, context, quote): """ This method is called for every market data tick update on the requested symbols. """ symbol_contexts = context.symbol_contexts[quote.symbol] # logging.debug("I'm evaluating the data for %s" % (quote, )) if len(symbol_contexts.quotes) > 25: # i.e. we have enough data quoteTimes = [ time.mktime(o.start_time.timetuple()) for o in symbol_contexts.quotes ] closePrices = asarray(symbol_contexts.closes) ema_10 = financial.ema(closePrices[-10:], 10) ema_25 = financial.ema(closePrices[-15:], 15) symbolContext.ema_10.append(ema_10) symbolContext.ema_25.append(ema_25) if ema_10 > ema_25: if context.symbolContexts[quote.symbol].position is False: # create a LONG position logging.debug("Opening position on quote: %s" % (quote, )) context.place_order( Order(quote.symbol, 1, Entry(Entry.Type.MARKET), Direction.LONG, stoploss=StopLoss(StopLoss.Type.FIXED, 20), take_profit=25)) context.symbol_contexts[quote.symbol].position = True else: if context.symbol_contexts[quote.symbol].position is True: context.symbol_contexts[quote.symbol].position = False
def evaluate_quote_update(self, context, quote): """ This method is called for every market data tick update on the requested symbols. """ symbol_context = context.get_quote_context(quote) if len(symbol_context.quotes) > self.space_to_left: # i.e. we have enough data # if quote.start_time.time() > datetime.time(21, 0) or quote.start_time.time() < datetime.time(7, 0): # # not normal EURUSD active period # return # if quote.start_time.weekday() >= 5: # # it's a weekend # return # if quote.start_time.weekday() == 4 and quote.start_time.time() > datetime.time(16, 0): # # no positions after 16:00 on Friday # return previous_quote = symbol_context.quotes[-1] # have we changed direction? if self.is_opposite(quote, previous_quote): # check if this candle engulfs the previous if self.is_body_engulfing(quote, previous_quote): historic_periods = list(symbol_context.quotes)[:-1] if self.is_largest(quote, historic_periods[-self.largest_body_count:]): # are we thinking about long or short? if quote.close < quote.open: # go short if self.is_strong_candle(quote, Direction.SHORT): if self.has_space_to_left_of_high(quote, previous_quote, historic_periods[-self.space_to_left:-1]): stop_points = (abs(quote.close - quote.high) * (quote.symbol.lot_size + 1)) + 5 stop_loss = StopLoss(StopLoss.Type.FIXED, stop_points) qty = self.calculate_position_size(context, stop_points) if qty > 0: context.place_order(Order(quote.symbol, qty, Entry(Entry.Type.LIMIT, quote.low - 5), Direction.SHORT, stoploss=stop_loss, take_profit=self.take_profit, expire_time=self.time_period)) else: # go long if self.is_strong_candle(quote, Direction.LONG): if self.has_space_to_left_of_low(quote, previous_quote, historic_periods[-self.space_to_left:-1]): stop_points = (abs(quote.close - quote.low) * (quote.symbol.lot_size + 1)) + 5 stop_loss = StopLoss(StopLoss.Type.FIXED, stop_points) qty = self.calculate_position_size(context, stop_points) if qty > 0: context.place_order(Order(quote.symbol, qty, Entry(Entry.Type.LIMIT, quote.high + 5), Direction.LONG, stoploss=stop_loss, take_profit=self.take_profit, expire_time=self.time_period))
def testShortLoss(self): s1 = Symbol.get("TEST") s1.lot_size = 10000 # LONG order = Order(s1, 1, Entry(Entry.Type.MARKET), Direction.SHORT) tick = Tick(datetime.utcnow(), 1.12239, 1.12245) # spread of 0.6 position = Position(order, tick) tick = Tick(datetime.utcnow(), 1.12259, 1.12265) position.close(tick) self.assertAlmostEquals(-2, position.points_delta())
def testModifiedStopLoss(self): s1 = Symbol.get("TEST") s1.lot_size = 10000 # LONG order = Order(s1, 1, Entry(Entry.Type.MARKET), Direction.SHORT) tick = Tick(datetime.utcnow(), 1.12239, 1.12245) # spread of 0.6 position = Position(order, tick) self.assertIsNone(position.stop_price) position.update(stop_loss=StopLoss(StopLoss.Type.FIXED, 2)) self.assertIsNotNone(position.stop_price) self.assertEqual(1.12265, position.stop_price)
def evaluate_quote_update(self, context, quote): """ This method is called for every market data tick update on the requested symbols. """ symbolContext = context.symbol_contexts[quote.symbol] # logging.debug("I'm evaluating the data for %s" % (quote, )) if len(symbolContext.quotes ) > self.emaPeriod: # i.e. we have enough data space = 5 if quote.start_time.time() > datetime.time( 21, 0) or quote.start_time.time() < datetime.time(7, 0): # not normal EURUSD active period return if quote.start_time.weekday() >= 5: # it's a weekend return if quote.start_time.weekday( ) == 4 and quote.start_time.time() > datetime.time(12, 0): # no positions after 12 on Friday return closePrices = asarray(symbolContext.closes) ema = financial.ema(closePrices[-self.emaPeriod:], self.emaPeriod) bar_height = symbolContext.high - symbolContext.low # bar_is_largest = bar_height > (symbolContext.highs[-1] - symbolContext.lows[-1]) bar_is_lowest = symbolContext.low < min( list(symbolContext.lows)[-space:-1]) bar_is_highest = symbolContext.high > max( list(symbolContext.highs)[-space:-1]) buy_signal = bar_is_lowest and ( (min(symbolContext.open, symbolContext.close) - symbolContext.low) * 1.5) >= (symbolContext.high - symbolContext.low) sell_signal = bar_is_highest and ( (symbolContext.high - max(symbolContext.open, symbolContext.close)) * 1.5) >= (symbolContext.high - symbolContext.low) open_positions = list(context.open_positions()) if quote.close > ema and sell_signal: # if context.quote_contexts[quote.symbol].position is False: # create a LONG position if len(open_positions) != 0: position = open_positions[0] if position.order.direction is Direction.SHORT: context.close_position(position) else: logging.debug("Opening position on quote: %s" % (quote, )) context.place_order( Order(quote.symbol, 50, Entry(Entry.Type.MARKET), Direction.SHORT, stoploss=self.stopLoss, take_profit=self.takeProfit)) # context.quote_contexts[quote.symbol].position = True elif quote.close < ema and buy_signal: if len(open_positions) != 0: position = open_positions[0] if position.order.direction is Direction.LONG: context.close_position(position) else: logging.debug("Opening position on quote: %s" % (quote, )) context.place_order( Order(quote.symbol, 50, Entry(Entry.Type.MARKET), Direction.SHORT, stoploss=self.stopLoss, take_profit=self.takeProfit))