def risk_managed_order(step: int, side: 'TradeSide', trade_type: 'TradeType', pair: 'TradingPair', price: float, size: float, down_percent: float, up_percent: float, portfolio: 'Portfolio', start: int = None, end: int = None): instrument = side.instrument(pair) order = Order(step=step, side=side, trade_type=trade_type, pair=pair, price=price, start=start, end=end, quantity=(size * instrument), portfolio=portfolio) risk_criteria = Stop("down", down_percent) ^ Stop("up", up_percent) risk_management = OrderSpec(side=TradeSide.SELL if side == TradeSide.BUY else TradeSide.BUY, trade_type=TradeType.MARKET, pair=pair, criteria=risk_criteria) order += risk_management return order
def risk_managed_order(step: int, side: 'TradeSide', trade_type: 'TradeType', pair: 'TradingPair', price: float, size: float, down_percent: float, up_percent: float, portfolio: 'Portfolio', ttl_in_seconds: int = None, ttl_in_steps: int = None): instrument = pair.base if side == TradeSide.BUY else pair.quote order = Order(step=step, side=side, trade_type=trade_type, pair=pair, price=price, ttl_in_seconds=ttl_in_seconds, ttl_in_steps=ttl_in_steps, quantity=(size * instrument), portfolio=portfolio) risk_criteria = Stop("down", down_percent) ^ Stop("up", up_percent) risk_management = OrderSpec( side=TradeSide.SELL if side == TradeSide.BUY else TradeSide.BUY, trade_type=TradeType.MARKET, pair=pair, criteria=risk_criteria) order += risk_management return order
def risk_managed_order(step: int, side: 'TradeSide', trade_type: 'TradeType', exchange_pair: 'ExchangePair', price: float, quantity: 'Quantity', down_percent: float, up_percent: float, portfolio: 'Portfolio', start: int = None, end: int = None): order = Order(step=step, side=side, trade_type=trade_type, exchange_pair=exchange_pair, price=price, start=start, end=end, quantity=quantity, portfolio=portfolio) risk_criteria = Stop("down", down_percent) ^ Stop("up", up_percent) risk_management = OrderSpec( side=TradeSide.SELL if side == TradeSide.BUY else TradeSide.BUY, trade_type=TradeType.MARKET, exchange_pair=exchange_pair, criteria=risk_criteria) order += risk_management return order
def risk_managed_order(side: 'TradeSide', trade_type: 'TradeType', pair: 'TradingPair', price: float, size: float, down_percent: float, up_percent: float, portfolio: 'Portfolio'): order = Order(side=side, trade_type=trade_type, pair=pair, price=price, quantity=(size * pair.base), portfolio=portfolio) risk_criteria = Stop("down", down_percent) ^ Stop("up", up_percent) risk_management = OrderSpec(side=TradeSide.SELL if side == TradeSide.BUY else TradeSide.BUY, trade_type=TradeType.MARKET, pair=pair, criteria=risk_criteria) order += risk_management return order
def test_is_executable_on(mock_portfolio_class, mock_exchange_class): exchange = mock_exchange_class.return_value exchange.name = "coinbase" portfolio = mock_portfolio_class.return_value # Market order order = Order(step=0, exchange_name="coinbase", side=TradeSide.BUY, trade_type=TradeType.MARKET, pair=USD/BTC, quantity=5000.00 * USD, portfolio=portfolio, price=7000.00) exchange.quote_price = mock.Mock(return_value=6800.00) assert order.is_executable_on(exchange) exchange.quote_price = mock.Mock(return_value=7200.00) assert order.is_executable_on(exchange) # Limit order order = Order(step=0, exchange_name="coinbase", side=TradeSide.BUY, trade_type=TradeType.LIMIT, pair=USD/BTC, quantity=5000.00 * USD, portfolio=portfolio, price=7000.00) exchange.quote_price = mock.Mock(return_value=6800.00) assert order.is_executable_on(exchange) exchange.quote_price = mock.Mock(return_value=7200.00) assert order.is_executable_on(exchange) # Stop Order order = Order(step=0, exchange_name="coinbase", side=TradeSide.SELL, trade_type=TradeType.LIMIT, pair=USD/BTC, quantity=5000.00 * USD, portfolio=portfolio, price=7000.00, criteria=Stop("down", 0.03)) exchange.quote_price = mock.Mock(return_value=(1 - 0.031)*order.price) assert order.is_executable_on(exchange) exchange.quote_price = mock.Mock(return_value=(1 - 0.02) * order.price) assert not order.is_executable_on(exchange)
def test_or(mock_order_class, mock_exchange_class): # Test Initialization criteria = Stop("down", 0.03) | Stop("up", 0.03) assert criteria assert isinstance(criteria, Criteria) order = mock_order_class.return_value order.pair = USD / BTC order.price = 7000.00 exchange = mock_exchange_class.return_value # Test (stop=True, stop=False) ===> True # Greater than 3.00% below order price exchange.quote_price.return_value = 0.95 * order.price assert criteria(order, exchange) # Equal to 3.00% below order price exchange.quote_price.return_value = 0.969 * order.price assert criteria(order, exchange) # Test (stop=False, stop=False) ===> False # Less than 3.00% below order price exchange.quote_price.return_value = 0.98 * order.price assert not criteria(order, exchange) # Less than 3.00% above order price exchange.quote_price.return_value = 1.02 * order.price assert not criteria(order, exchange) # Test (stop=False, stop=True) ===> True # Equal to 3.00% above order price exchange.quote_price.return_value = 1.031 * order.price assert criteria(order, exchange) # Greater than 3.00% above order price exchange.quote_price.return_value = 1.05 * order.price assert criteria(order, exchange)
def test_call_with_direction_up(mock_order_class, mock_exchange_class): exchange = mock_exchange_class.return_value order = mock_order_class.return_value order.pair = USD / BTC order.price = 7000.00 criteria = Stop(direction=StopDirection.UP, percent=0.03) # Less than 3.00% above order price exchange.quote_price.return_value = 1.02 * order.price assert not criteria(order, exchange) # Equal to 3.00% above order price exchange.quote_price.return_value = 1.031 * order.price assert criteria(order, exchange) # Greater than 3.00% above order price exchange.quote_price.return_value = 1.05 * order.price assert criteria(order, exchange)
def test_call_with_direction_down(mock_order_class, mock_exchange_class): exchange = mock_exchange_class.return_value order = mock_order_class.return_value order.pair = USD / BTC order.price = 7000.00 criteria = Stop(direction=StopDirection.DOWN, percent=0.03) # Greater than 3.00% below order price exchange.quote_price.return_value = 0.95 * order.price assert criteria(order, exchange) # Equal to 3.00% below order price exchange.quote_price.return_value = 0.969 * order.price assert criteria(order, exchange) # Less than 3.00% below order price exchange.quote_price.return_value = 0.98 * order.price assert not criteria(order, exchange)
def test_is_executable_on(mock_exchange_class): exchange = mock_exchange_class.return_value exchange.options = ExchangeOptions() exchange.id = "fake_exchange_id" exchange.name = "coinbase" exchange.clock = mock.Mock() exchange.clock.step = 0 # Market order wallets = [Wallet(exchange, 10000 * USD), Wallet(exchange, 0 * BTC)] portfolio = Portfolio(USD, wallets) order = Order(step=0, exchange_pair=ExchangePair(exchange, USD / BTC), side=TradeSide.BUY, trade_type=TradeType.MARKET, quantity=5000.00 * USD, portfolio=portfolio, price=Decimal(7000.00)) exchange.quote_price = mock.Mock(return_value=Decimal(6800.00)) assert order.is_executable() exchange.quote_price = mock.Mock(return_value=Decimal(7200.00)) assert order.is_executable() # Limit order wallets = [Wallet(exchange, 10000 * USD), Wallet(exchange, 0 * BTC)] portfolio = Portfolio(USD, wallets) order = Order(step=0, exchange_pair=ExchangePair(exchange, USD / BTC), side=TradeSide.BUY, trade_type=TradeType.LIMIT, quantity=5000.00 * USD, portfolio=portfolio, price=Decimal(7000.00)) exchange.quote_price = mock.Mock(return_value=Decimal(6800.00)) assert order.is_executable() exchange.quote_price = mock.Mock(return_value=Decimal(7200.00)) assert order.is_executable() # Stop Order wallets = [Wallet(exchange, 0 * USD), Wallet(exchange, 2 * BTC)] portfolio = Portfolio(USD, wallets) order = Order(step=0, exchange_pair=ExchangePair(exchange, USD / BTC), side=TradeSide.SELL, trade_type=TradeType.LIMIT, quantity=1 * BTC, portfolio=portfolio, price=Decimal(7000.00), criteria=Stop("down", 0.03)) exchange.quote_price = mock.Mock(return_value=Decimal(1 - 0.031) * order.price) assert order.is_executable() exchange.quote_price = mock.Mock(return_value=Decimal(1 - 0.02) * order.price) assert not order.is_executable()
def test_complete_complex_order(mock_trade_class, mock_exchange_class): exchange = mock_exchange_class.return_value exchange.options = ExchangeOptions() exchange.id = "fake_exchange_id" exchange.name = "coinbase" exchange.clock = mock.Mock() exchange.clock.step = 0 exchange.quote_price = mock.Mock(return_value=Decimal(7000.00)) wallets = [Wallet(exchange, 10000 * USD), Wallet(exchange, 0 * BTC)] portfolio = Portfolio(USD, wallets) side = TradeSide.BUY order = Order(step=0, exchange_pair=ExchangePair(exchange, USD / BTC), side=TradeSide.BUY, trade_type=TradeType.MARKET, quantity=5200.00 * USD, portfolio=portfolio, price=Decimal(7000.00)) risk_criteria = Stop("down", 0.03) ^ Stop("up", 0.02) risk_management = OrderSpec( side=TradeSide.SELL if side == TradeSide.BUY else TradeSide.BUY, trade_type=TradeType.MARKET, exchange_pair=ExchangePair(exchange, USD / BTC), criteria=risk_criteria) order += risk_management order.execute() # Execute fake trade price = Decimal(7010.00) scale = order.price / price commission = 3.00 * USD base_size = scale * order.size - commission.size trade = mock_trade_class.return_value trade.size = Decimal(base_size) trade.quantity = base_size * USD trade.price = price trade.commission = commission base_wallet = portfolio.get_wallet(exchange.id, USD) quote_wallet = portfolio.get_wallet(exchange.id, BTC) base_size = trade.size + trade.commission.size quote_size = (order.price / trade.price) * (trade.size / trade.price) base_wallet.withdraw(quantity=Quantity(USD, size=base_size, path_id=order.path_id), reason="test") quote_wallet.deposit(quantity=Quantity(BTC, size=quote_size, path_id=order.path_id), reason="test") # Fill fake trade order.fill(trade) assert order.path_id in portfolio.get_wallet(exchange.id, USD).locked assert order.status == OrderStatus.PARTIALLY_FILLED next_order = order.complete() assert order.status == OrderStatus.FILLED assert next_order assert next_order.path_id == order.path_id assert next_order.size assert next_order.status == OrderStatus.PENDING assert next_order.side == TradeSide.SELL assert next_order.exchange_pair == ExchangePair(exchange, USD / BTC)
def test_on_fill_with_complex_order(mock_trade_class, mock_exchange_class): exchange = mock_exchange_class.return_value exchange.options.max_trade_size = 1e6 exchange.id = "fake_exchange_id" exchange.name = "coinbase" exchange.quote_price = lambda pair: Decimal(7000.00) broker = Broker() broker.exchanges = [exchange] wallets = [Wallet(exchange, 10000 * USD), Wallet(exchange, 0 * BTC)] portfolio = Portfolio(USD, wallets) side = TradeSide.BUY order = Order(step=0, exchange_pair=ExchangePair(exchange, USD / BTC), side=TradeSide.BUY, trade_type=TradeType.MARKET, quantity=5200.00 * USD, portfolio=portfolio, price=Decimal(7000.00)) risk_criteria = Stop("down", 0.03) ^ Stop("up", 0.02) risk_management = OrderSpec( side=TradeSide.SELL if side == TradeSide.BUY else TradeSide.BUY, trade_type=TradeType.MARKET, exchange_pair=ExchangePair(exchange, USD / BTC), criteria=risk_criteria) order += risk_management order.attach(broker) order.execute() broker._executed[order.id] = order # Execute fake trade price = Decimal(7000.00) scale = order.price / price commission = 3.00 * USD base_size = scale * order.size - commission.size trade = mock_trade_class.return_value trade.order_id = order.id trade.size = base_size trade.quantity = base_size * USD trade.price = price trade.commission = commission base_wallet = portfolio.get_wallet(exchange.id, USD) quote_wallet = portfolio.get_wallet(exchange.id, BTC) base_size = trade.size + trade.commission.size quote_size = (order.price / trade.price) * (trade.size / trade.price) base_wallet.withdraw(quantity=Quantity(USD, size=base_size, path_id=order.path_id), reason="test") quote_wallet.deposit(quantity=Quantity(BTC, size=quote_size, path_id=order.path_id), reason="test") assert trade.order_id in broker.executed.keys() assert trade not in broker.trades assert broker.unexecuted == [] order.fill(trade) assert order.remaining == 0 assert trade in broker.trades[order.id] assert broker.unexecuted != []
def test_complete_complex_order(mock_trade_class, mock_exchange_class): exchange = mock_exchange_class.return_value exchange.id = "fake_exchange_id" wallets = [Wallet(exchange, 10000 * USD), Wallet(exchange, 0 * BTC)] portfolio = Portfolio(USD, wallets) side = TradeSide.BUY order = Order(step=0, side=TradeSide.BUY, trade_type=TradeType.MARKET, pair=USD / BTC, quantity=5200.00 * USD, portfolio=portfolio, price=7000.00) risk_criteria = Stop("down", 0.03) ^ Stop("up", 0.02) risk_management = OrderSpec(side=TradeSide.SELL if side == TradeSide.BUY else TradeSide.BUY, trade_type=TradeType.MARKET, pair=USD / BTC, criteria=risk_criteria) order += risk_management order.execute(exchange) # Execute fake trade price = 7010.00 scale = order.price / price commission = 3.00 * USD base_size = scale * order.size - commission.size trade = mock_trade_class.return_value trade.size = base_size trade.price = price trade.commission = commission base_wallet = portfolio.get_wallet(exchange.id, USD) quote_wallet = portfolio.get_wallet(exchange.id, BTC) base_size = trade.size + trade.commission.size quote_size = (order.price / trade.price) * (trade.size / trade.price) base_wallet -= Quantity(USD, size=base_size, path_id=order.path_id) quote_wallet += Quantity(BTC, size=quote_size, path_id=order.path_id) # Fill fake trade order.fill(exchange, trade) assert order.path_id in portfolio.get_wallet(exchange.id, USD).locked assert order.status == OrderStatus.PARTIALLY_FILLED next_order = order.complete(exchange) assert order.status == OrderStatus.FILLED assert next_order assert next_order.path_id == order.path_id assert next_order.size assert next_order.status == OrderStatus.PENDING assert next_order.side == TradeSide.SELL assert next_order.pair == USD/BTC
def test_on_fill_with_complex_order(mock_trade_class, mock_exchange_class): exchange = mock_exchange_class.return_value exchange.id = "fake_exchange_id" broker = Broker(exchange) wallets = [Wallet(exchange, 10000 * USD), Wallet(exchange, 0 * BTC)] portfolio = Portfolio(USD, wallets) side = TradeSide.BUY order = Order(step=0, side=TradeSide.BUY, trade_type=TradeType.MARKET, pair=USD / BTC, quantity=5200.00 * USD, portfolio=portfolio, price=7000.00) risk_criteria = Stop("down", 0.03) ^ Stop("up", 0.02) risk_management = OrderSpec( side=TradeSide.SELL if side == TradeSide.BUY else TradeSide.BUY, trade_type=TradeType.MARKET, pair=USD / BTC, criteria=risk_criteria) order += risk_management order.attach(broker) order.execute(exchange) broker._executed[order.id] = order # Execute fake trade price = 7000.00 scale = order.price / price commission = 3.00 * USD base_size = scale * order.size - commission.size trade = mock_trade_class.return_value trade.order_id = order.id trade.size = base_size trade.price = price trade.commission = commission base_wallet = portfolio.get_wallet(exchange.id, USD) quote_wallet = portfolio.get_wallet(exchange.id, BTC) base_size = trade.size + trade.commission.size quote_size = (order.price / trade.price) * (trade.size / trade.price) base_wallet -= Quantity(USD, size=base_size, path_id=order.path_id) quote_wallet += Quantity(BTC, size=quote_size, path_id=order.path_id) assert trade.order_id in broker.executed.keys() assert trade not in broker.trades assert broker.unexecuted == [] order.fill(exchange, trade) assert order.remaining_size == 0 assert trade in broker.trades[order.id] assert broker.unexecuted != []
def test_str(): criteria = Stop(direction=StopDirection.UP, percent=0.3) assert str(criteria) == "<Stop: direction=up, percent=0.3>"
def test_init(): criteria = Stop(direction=StopDirection.UP, percent=0.3) assert criteria.direction == StopDirection.UP assert criteria.percent == 0.3