예제 #1
0
    def _from_ib_trade(self, ib_trade: _IBTrade) -> Trade:
        contract = self._from_ib_contract(ib_contract=ib_trade.contract)
        order = self._from_ib_order(ib_order=ib_trade.order)
        status = self._from_ib_status(ib_order_status=ib_trade.orderStatus)
        trade = Trade(contract=contract, order=order, status=status)

        return trade
예제 #2
0
def test_subscribe_to_position_updates():
    con = StockContract(symbol="SPY")
    pos = Position(
        account=DEFAULT_SIM_ACC,
        contract=con,
        position=10,
        ave_fill_price=345.6,
    )
    starting_positions = {
        DEFAULT_SIM_ACC: {con: pos},
    }
    untethered_sim_broker = SimulationBroker(
        sim_streamer=SimulationDataStreamer(),
        starting_funds={Currency.USD: 10_000},
        transaction_cost=1,
        starting_positions=starting_positions,
    )

    pos_updates = []

    def pos_updates_receiver(pos_: Position):
        pos_updates.append(pos_)

    untethered_sim_broker.subscribe_to_position_updates(
        func=pos_updates_receiver,
    )
    sim_order = LimitOrder(action=OrderAction.BUY, quantity=2, limit_price=346)
    sim_trade = Trade(contract=con, order=sim_order)
    untethered_sim_broker.place_trade(trade=sim_trade)
    untethered_sim_broker.simulate_trade_execution(
        trade=sim_trade, price=345.8, n_shares=1,
    )
    untethered_sim_broker.step()

    assert len(pos_updates) == 1

    updated_pos: Position = pos_updates[0]
    target_ave_price = (10 * 345.6 + 345.8) / 11

    assert updated_pos.contract == con
    assert updated_pos.position == 11
    assert updated_pos.ave_fill_price == target_ave_price
    assert updated_pos.account == DEFAULT_SIM_ACC

    untethered_sim_broker.simulate_trade_execution(
        trade=sim_trade, price=345.9, n_shares=1,
    )
    untethered_sim_broker.step()

    updated_pos: Position = pos_updates[1]
    target_ave_price = (target_ave_price * 11 + 345.9) / 12

    assert updated_pos.contract == con
    assert updated_pos.position == 12
    assert updated_pos.ave_fill_price == target_ave_price
    assert updated_pos.account == DEFAULT_SIM_ACC
예제 #3
0
def get_1_spy_mkt_trade(buy: bool) -> Trade:
    contract = StockContract(symbol="SPY")

    if buy:
        action = OrderAction.BUY
    else:
        action = OrderAction.SELL

    order = MarketOrder(action=action, quantity=1)
    trade = Trade(contract=contract, order=order)

    return trade
예제 #4
0
    def _execute_trade(
        self,
        trade: Trade,
        price: Optional[float] = None,
        n_shares: Optional[float] = None,
    ):

        trade_idx = self._placed_trades.index(trade)
        trade = self._placed_trades[trade_idx]

        self._validate_trade_execution(
            trade=trade,
            price=price,
            n_shares=n_shares,
        )

        contract = trade.contract
        order = trade.order
        filled = trade.status.filled

        if n_shares is None:
            n_shares = order.quantity - filled

        if price is None:
            price = self._get_current_price(contract=contract)

        if order.action == OrderAction.BUY:
            funds_delta = -(n_shares * price + self.get_transaction_fee())
            shares_delta = n_shares
        else:
            funds_delta = n_shares * price + self.get_transaction_fee()
            shares_delta = -n_shares
        self.acc_cash[contract.currency] += funds_delta
        self._add_to_position(
            contract=contract,
            n_shares=shares_delta,
            fill_price=price,
        )

        filled = trade.status.filled
        new_filled = filled + n_shares
        ave_price = trade.status.ave_fill_price
        new_ave_price = (ave_price * filled + price * n_shares) / new_filled
        new_status = TradeStatus(
            state=TradeState.FILLED,
            filled=new_filled,
            remaining=order.quantity - new_filled,
            ave_fill_price=new_ave_price,
            order_id=order.order_id,
        )
        trade.status = new_status
        self._update_trade_updates_subscribers(trade=trade)
예제 #5
0
    def cancel_trade(self, trade: Trade):
        # TODO: test
        cancelled_status = TradeStatus(
            state=TradeState.CANCELLED,
            filled=trade.status.filled,
            remaining=trade.status.remaining,
            ave_fill_price=trade.status.ave_fill_price,
            order_id=trade.status.order_id,
        )
        new_trade = Trade(
            contract=trade.contract,
            order=trade.order,
            status=cancelled_status,
        )
        trade_idx = self._placed_trades.index(trade)
        self._placed_trades[trade_idx] = new_trade

        self._update_trade_updates_subscribers(trade=trade)
예제 #6
0
def test_simulation_broker_limit_order(sim_broker_runner_and_streamer_15m):
    broker, runner, _ = sim_broker_runner_and_streamer_15m

    assert len(broker.open_trades) == 0

    contract = StockContract(symbol="SPY")
    order = LimitOrder(action=OrderAction.SELL, quantity=2, limit_price=99,)
    trade = Trade(contract=contract, order=order)

    runner.run_sim(step_count=1)
    _, trade = broker.place_trade(trade=trade, order=order)
    runner.run_sim(step_count=1)

    assert trade.status.state == TradeState.SUBMITTED

    broker.simulate_trade_execution(
        trade=trade, price=100, n_shares=1,
    )

    # does not update without sim step
    assert trade.status.state == TradeState.SUBMITTED

    runner.run_sim(step_count=1)

    assert trade.status.state == TradeState.FILLED
    assert trade.status.filled == 1
    assert trade.status.remaining == 1

    broker.simulate_trade_execution(
        trade=trade, price=100, n_shares=1,
    )

    runner.run_sim(step_count=1)

    assert trade.status.state == TradeState.FILLED
    assert trade.status.filled == 2
    assert trade.status.remaining == 0
예제 #7
0
    def place_trade(
        self,
        trade: Trade,
        *args,
        trade_execution_price: Optional[float] = None,
        trade_execution_size: Optional[float] = None,
        **kwargs,
    ) -> Tuple[bool, Trade]:
        trade_id = self._get_increment_valid_id()
        order = trade.order
        order._order_id = trade_id
        new_status = TradeStatus(
            state=TradeState.SUBMITTED,
            filled=0,
            remaining=order.quantity,
            ave_fill_price=0,
            order_id=trade_id,
        )
        new_trade = Trade(
            contract=trade.contract,
            order=order,
            status=new_status,
        )
        self._placed_trades.append(new_trade)

        self._update_trade_updates_subscribers(trade=new_trade)

        if isinstance(trade.order, MarketOrder):
            self._scheduled_trade_executions.append(
                (trade, trade_execution_price, trade_execution_size))

        # update trade placed subscribers
        for func, fn_kwargs in self._new_trade_subscribers:
            func(trade, **fn_kwargs)

        return True, new_trade