Esempio n. 1
0
    def generate_order_and_txns(self, sid, order_amount, fill_amounts):
        asset1 = self.asset_finder.retrieve_asset(sid)

        # one order
        order = Order(dt=None, asset=asset1, amount=order_amount)

        # three fills
        txn1 = Transaction(asset=asset1,
                           amount=fill_amounts[0],
                           dt=None,
                           price=100,
                           order_id=order.id)

        txn2 = Transaction(asset=asset1,
                           amount=fill_amounts[1],
                           dt=None,
                           price=101,
                           order_id=order.id)

        txn3 = Transaction(asset=asset1,
                           amount=fill_amounts[2],
                           dt=None,
                           price=102,
                           order_id=order.id)

        return order, [txn1, txn2, txn3]
Esempio n. 2
0
    def simulate(self, data, asset, orders_for_asset):
        self._volume_for_bar = 0

        price = data.current(asset, 'close')

        dt = data.current_dt
        for order in orders_for_asset:
            if order.open_amount == 0:
                continue

            order.check_triggers(price, dt)
            if not order.triggered:
                log.debug('order has not reached the trigger at current '
                          'price {}'.format(price))
                continue

            execution_price, execution_volume = self.process_order(data, order)

            transaction = Transaction(asset=order.asset,
                                      amount=abs(execution_volume),
                                      dt=dt,
                                      price=execution_price,
                                      order_id=order.id)

            self._volume_for_bar += abs(transaction.amount)
            yield order, transaction
Esempio n. 3
0
def create_txn(asset, price, amount, datetime, order_id):
    return Transaction(
        asset=asset,
        price=price,
        amount=amount,
        dt=datetime,
        order_id=order_id,
    )
Esempio n. 4
0
    def process_order(self, order):
        # TODO: move to parent class after tracking features in the parent
        if not self.api.hasFetchMyTrades:
            return self._process_order_fallback(order)

        try:
            all_trades = self.get_trades(order.asset)
        except ExchangeRequestError as e:
            log.warn(
                'unable to fetch account trades, trying an alternate '
                'method to find executed order {} / {}: {}'.format(
                    order.id, order.asset.symbol, e
                )
            )
            return self._process_order_fallback(order)

        transactions = []
        trades = [t for t in all_trades if t['order'] == order.id]
        if not trades:
            log.debug(
                'order {} / {} not found in trades'.format(
                    order.id, order.asset.symbol
                )
            )
            return transactions

        trades.sort(key=lambda t: t['timestamp'], reverse=False)
        order.filled = 0
        order.commission = 0
        for trade in trades:
            # status property will update automatically
            filled = trade['amount'] * order.direction
            order.filled += filled

            commission = 0
            if 'fee' in trade and 'cost' in trade['fee']:
                commission = trade['fee']['cost']
                order.commission += commission

            order.check_triggers(
                price=trade['price'],
                dt=pd.to_datetime(trade['timestamp'], unit='ms', utc=True),
            )
            transaction = Transaction(
                asset=order.asset,
                amount=filled,
                dt=pd.Timestamp.utcnow(),
                price=trade['price'],
                order_id=order.id,
                commission=commission
            )
            transactions.append(transaction)

        order.broker_order_id = ', '.join([t['id'] for t in trades])
        return transactions
Esempio n. 5
0
    def test_transaction_repr(self):
        dt = pd.Timestamp('2017-01-01')

        asset = Equity(1, exchange='test')
        txn = Transaction(asset, amount=100, dt=dt, price=10, order_id=0)

        expected = (
            "Transaction(asset=Equity(1), dt=2017-01-01 00:00:00,"
            " amount=100, price=10)"
        )

        self.assertEqual(repr(txn), expected)
Esempio n. 6
0
    def _process_order_fallback(self, order):
        """
        Fallback method for exchanges which do not play nice with
        fetch-my-trades. Apparently, about 60% of exchanges will return
        the correct executed values with this method. Others will support
        fetch-my-trades.

        Parameters
        ----------
        order: Order

        Returns
        -------
        float

        """
        exc_order, price = self.get_order(
            order.id,
            order.asset,
            return_price=True,
            params={'type': order.direction_type})
        order.status = exc_order.status
        order.commission = exc_order.commission
        order.filled = exc_order.filled
        order.matched_price = price
        order.dt = exc_order.dt

        transactions = []
        if exc_order.status == ORDER_STATUS.FILLED or \
                (exc_order.status == ORDER_STATUS.CANCELLED and exc_order.filled != 0):
            if order.amount != exc_order.amount:
                log.warn('order({}): executed amount {} differs '
                         'from original {}'.format(order.id, exc_order.amount,
                                                   order.amount))

            order.check_triggers(
                price=price,
                dt=exc_order.dt,
            )
            transaction = Transaction(
                asset=order.asset,
                amount=exc_order.filled,
                dt=pd.Timestamp.utcnow(),
                price=price,
                order_id=order.id,
                commission=order.commission,
            )
            transactions.append(transaction)

        return transactions
Esempio n. 7
0
    def check_open_orders(self):
        """
        Loop through the list of open orders in the Portfolio object.
        For each executed order found, create a transaction and apply to the
        Portfolio.

        Returns
        -------
        list[Transaction]

        """
        for asset in self.open_orders:
            exchange = self.exchanges[asset.exchange]

            for order in self.open_orders[asset]:
                log.debug('found open order: {}'.format(order.id))

                new_order, executed_price = exchange.get_order(order.id, asset)
                log.debug('got updated order {} {}'.format(
                    new_order, executed_price))
                order.status = new_order.status

                if order.status == ORDER_STATUS.FILLED:
                    order.commission = new_order.commission
                    if order.amount != new_order.amount:
                        log.warn('executed order amount {} differs '
                                 'from original'.format(
                                     new_order.amount, order.amount))
                        order.amount = new_order.amount

                    transaction = Transaction(asset=order.asset,
                                              amount=order.amount,
                                              dt=pd.Timestamp.utcnow(),
                                              price=executed_price,
                                              order_id=order.id,
                                              commission=order.commission)
                    yield order, transaction

                elif order.status == ORDER_STATUS.CANCELLED:
                    yield order, None

                else:
                    delta = pd.Timestamp.utcnow() - order.dt
                    log.info(
                        'order {order_id} still open after {delta}'.format(
                            order_id=order.id, delta=delta))
Esempio n. 8
0
    def _process_order_fallback(self, order):
        """
        Fallback method for exchanges which do not play nice with
        fetch-my-trades. Apparently, about 60% of exchanges will return
        the correct executed values with this method. Others will support
        fetch-my-trades.

        Parameters
        ----------
        order: Order

        Returns
        -------
        float

        """
        exc_order, price = self.get_order(
            order.id, order.asset, return_price=True
        )
        order.status = exc_order.status

        order.commission = exc_order.commission
        if order.amount != exc_order.amount:
            log.warn(
                'executed order amount {} differs '
                'from original'.format(
                    exc_order.amount, order.amount
                )
            )
            order.amount = exc_order.amount

        if order.status == ORDER_STATUS.FILLED:
            transaction = Transaction(
                asset=order.asset,
                amount=order.amount,
                dt=pd.Timestamp.utcnow(),
                price=price,
                order_id=order.id,
                commission=order.commission
            )
        return [transaction]
Esempio n. 9
0
    def maybe_create_close_position_transaction(self, asset, dt, data_portal):
        if not self.positions.get(asset):
            return None

        amount = self.positions.get(asset).amount
        price = data_portal.get_spot_value(
            asset, 'price', dt, self.data_frequency)

        # Get the last traded price if price is no longer available
        if isnan(price):
            price = self.positions.get(asset).last_sale_price

        txn = Transaction(
            asset=asset,
            amount=(-1 * amount),
            dt=dt,
            price=price,
            commission=0,
            order_id=None,
        )
        return txn
Esempio n. 10
0
    def check_open_orders(self):
        """
        Loop through the list of open orders in the Portfolio object.
        For each executed order found, create a transaction and apply to the
        Portfolio.

        Returns
        -------
        list[Transaction]

        """
        transactions = list()
        if self.portfolio.open_orders:
            for order_id in list(self.portfolio.open_orders):
                log.debug('found open order: {}'.format(order_id))

                order, executed_price = self.get_order(order_id)
                log.debug('got updated order {} {}'.format(
                    order, executed_price))

                if order.status == ORDER_STATUS.FILLED:
                    transaction = Transaction(asset=order.asset,
                                              amount=order.amount,
                                              dt=pd.Timestamp.utcnow(),
                                              price=executed_price,
                                              order_id=order.id,
                                              commission=order.commission)
                    transactions.append(transaction)

                    self.portfolio.execute_order(order, transaction)

                elif order.status == ORDER_STATUS.CANCELLED:
                    self.portfolio.remove_order(order)

                else:
                    delta = pd.Timestamp.utcnow() - order.dt
                    log.info(
                        'order {order_id} still open after {delta}'.format(
                            order_id=order_id, delta=delta))
        return transactions
Esempio n. 11
0
    def check_open_orders(self):
        """
        Need to override this function for Poloniex:

        Loop through the list of open orders in the Portfolio object.
        Check if any transactions have been executed:
            If so, create a transaction and apply to the Portfolio.
        Check if the order is still open:
            If not, remove it from open orders

        :return:
        transactions: Transaction[]
        """
        transactions = list()
        if self.portfolio.open_orders:
            for order_id in list(self.portfolio.open_orders):

                order = self._portfolio.open_orders[order_id]
                log.debug('found open order: {}'.format(order_id))

                try:
                    order_open = self.get_order(order_id)
                except Exception as e:
                    raise ExchangeRequestError(error=e)

                if (order_open):
                    delta = pd.Timestamp.utcnow() - order.dt
                    log.info(
                        'order {order_id} still open after {delta}'.format(
                            order_id=order_id, delta=delta))

                try:
                    response = self.api.returnordertrades(order_id)
                except Exception as e:
                    raise ExchangeRequestError(error=e)

                if ('error' in response):
                    if (not order_open):
                        raise OrphanOrderReverseError(order_id=order_id,
                                                      exchange=self.name)
                else:
                    for tx in response:
                        """
                        We maintain a list of dictionaries of transactions that
                        correspond to partially filled orders, indexed by
                        order_id. Every time we query executed transactions
                        from the exchange, we check if we had that transaction
                        for that order already. If not, we process it.

                        When an order if fully filled, we flush the dict of
                        transactions associated with that order.
                        """
                        if (not filter(
                                lambda item: item['order_id'] == tx['tradeID'],
                                self.transactions[order_id])):
                            log.debug(
                                'Got new transaction for order {}: amount {}, '
                                'price {}'.format(order_id, tx['amount'],
                                                  tx['rate']))
                            tx['amount'] = float(tx['amount'])
                            if (tx['type'] == 'sell'):
                                tx['amount'] = -tx['amount']
                            transaction = Transaction(
                                asset=order.asset,
                                amount=tx['amount'],
                                dt=pd.to_datetime(tx['date'], utc=True),
                                price=float(tx['rate']),
                                order_id=tx['tradeID'],
                                # it's a misnomer, but keep for compatibility
                                commission=float(tx['fee']))
                            self.transactions[order_id].append(transaction)
                            self.portfolio.execute_transaction(transaction)
                            transactions.append(transaction)

                    if (not order_open):
                        """
                            Since transactions have been executed individually
                            the only thing left to do is remove them from list
                            of open_orders
                        """
                        del self.portfolio.open_orders[order_id]
                        del self.transactions[order_id]

        return transactions