Esempio n. 1
0
 def __init__(self, cash, database):
     """
     In order to simualte the T+1 market, in this class, I have added the
     old order and the new order variable. The new order is the order deal
     today, so it can not sell immediately. After every day, new order and
     the old order will be combine together, and the new order will be empty.
     :param cash:
     :param database:
     :return:
     """
     self._cash = cash
     self._stock_asset = {}
     self._order_book = OrderBook()
     self._new_order = {}
     self._old_order = {}
     self._puttable_order = {}
     # Account should have ability to connect the database.
     self._dbbase = database
Esempio n. 2
0
class Account(Configurable):
    """
    This is the core class in the simulator, since account is the center of
    my framework, it connect the market and the algorithm(which is human in
    general). So this class must be well designed.
    """
    def set_to_context(self, context):
        pass

    def get_from_context(self, context):
        pass

    def __init__(self, cash, database):
        """
        In order to simualte the T+1 market, in this class, I have added the
        old order and the new order variable. The new order is the order deal
        today, so it can not sell immediately. After every day, new order and
        the old order will be combine together, and the new order will be empty.
        :param cash:
        :param database:
        :return:
        """
        self._cash = cash
        self._stock_asset = {}
        self._order_book = OrderBook()
        self._new_order = {}
        self._old_order = {}
        self._puttable_order = {}
        # Account should have ability to connect the database.
        self._dbbase = database

    @property
    def cash(self):
        return self._cash

    @cash.setter
    def cash(self, cash):
        self._cash = cash

    def init_from_config(self, config, **kwargs):
        """
        Read config from the main config file.
        :param config:
        :param kwargs:
        :return:
        """
        if self.this_key in config:
            config_dict = config[self.this_key]
        else:
            raise ValueError("Do not have the key")
        self._cash = config_dict[self.key_cash]

    @property
    def cash(self):
        return self._cash

    @cash.setter
    def cash(self, cash):
        self._cash = cash

    def add_cash(self, added_cash):
        self._cash = added_cash

    def reset(self, cash, database):
        self.__init__(cash, database)

    def get_asset(self, date):
        stock_asset = 0
        for key in self._stock_asset:
            current_price = self._dbbase.get(key, date)
            self._stock_asset[key].current_price = current_price
            stock_asset += self._stock_asset[key].current_price * \
                           self._stock_asset[key].number
        return self._cash + stock_asset

    def position(self):
        return self._cash / self._origin_cash

    def buy(self, order, market=None):
        if market is None:
            raise ValueError("Invalid market")
        #TODO: Make clear the number of the order is 100 based or 1 based.
        if order.price*order.number > self._cash:
            raise ValueError("Do not have so much money")

        if market.process_order(order):
            self._order_book.add_order(order)
            # Add order to the asset.
            if order.name in self._stock_asset:
                self._stock_asset[order.name] += order
            else:
                self._stock_asset[order.name] = order
            # Add order to the new order.
            if order.name in self._new_order:
                self._new_order[order.name] += order
            else:
                self._new_order[order.name] = order
            self._cash = self._cash-order.price*order.number
        else:
            return False

    def sell(self, order, market=None):
        """
        Sell order, there are some other process method should add.
        :param order:
        :param market:
        :return:
        """
        if market is None:
            raise ValueError("Invalid market")
        # print "This is order name :", order.name
        # print self._old_order
        # Check if order in the old order
        if order.name not in self._old_order:
            raise ValueError("Do not have such stock asset")
        if order.number > self._old_order[order.name].number:
            raise ValueError("Can not sell too much")
        # print self._stock_asset
        # print self._old_order
        # Flash the order in the old order and the stock asset.
        if market.process_order(order):
            self._order_book.add_order(order)
            self._stock_asset[order.name] += order
            # clean the stock
            if self._stock_asset[order.name].number == 0:
                del self._stock_asset[order.name]
            self._old_order[order.name] += order
            if self._old_order[order.name].number == 0:
                del self._old_order[order.name]

            self._cash += order.price*order.number
            return True
        else:
            return False

    def _before_market(self, date):
        """
        process the data before the market open.
        :param date:
        :return:
        """
        return None

    def after_market(self, date):
        """
        Process the data after the market close.
        :param date: type str
        :return:
        """
        for key in self._stock_asset:
            data = self._dbbase.get_dataframe(key, begin=date, end=date)
            self._stock_asset[key].current_price = data.close.values[-1]
        # Combine the old_order and new_order
        for name in self._new_order:
            if name in self._old_order:
                self._old_order[name] += self._new_order[name]
            else:
                self._old_order[name] = self._new_order[name]
            self._new_order = {}
        self._update_asset(date)

    def _update_asset(self, date):
        """
        Update the asset result.
        :param date:
        :return:
        """
        for key in self._stock_asset:
            stock_asset = self._stock_asset[key]
            data = self._dbbase.get_dataframe(stock_asset.name, begin=date,
                                              end=date)
            stock_asset.current_price = data.close.values[-1]

    def get_return(self, date):
        """
        Get every stock asset's return, may be I should remove this method.
        :param date:
        :return:
        """
        for name in self._old_order:
            try:
                # print name, date
                # logger.debug("name is {name}, date is {date}".format(name=name,
                #                                                      date=date))
                data = self._dbbase.get_dataframe(name, begin=date, end=date)
                close_price = data.close.values[-1]
                self._old_order[name].current_price = close_price
                self._old_order[name].return_rate = (self._old_order[name].current_price
                                                     - self._old_order[name].price)/\
                                                    self._old_order[name].price

            except Exception as e:
                logger.exception(e.message)
                print e.message
                print 'error at date:', date, ' name:', name

    def get_stock_asset(self):
        return self._old_order

    def create_buy_order(self, name, price, context, position=1.0):
        """
        This function is used to create buy order by some parameter.
        :param name:
        :param price:
        :param tax_processor:
        :param position:
        :return:
        """
        logger.info("create buy order at time {date}".format(date=context.date))
        used_cash = self._cash * position
        buy_price = context.tax_processor.calculate_buy_tax(price)
        # Here we use 1 based count method.
        number = np.floor(used_cash/(buy_price*100))*100
        # print 'this is the buy number', number, 'cost money', buy_price*number
        order = Order(name=name, price=buy_price, date=context.date,
                      number=number,
                      current_price=price,
                      buy=True)
        return order

    def create_sell_order(self, name, price, context, position=1.0):
        """
        This function is used to create sell order by some parameter.
        :param name:
        :param price:
        :param date:
        :param tax_processor:
        :param position:
        :return:
        """
        if name not in self._old_order:
            raise ValueError('Stock not in the order list')
        order = self._old_order[name]
        # sell_price = context.tax_processor_calculate_sell_tax(price)
        sell_price = price
        sell_number = np.floor(order.number*position)
        # print 'this is the sell number', sell_number, 'cost money', sell_price*sell_number
        return Order(name=name, price=sell_price,
                     current_price=price,
                     date=context.date,
                     number=sell_number, sell=True)

    def get_cash(self):
        """
        get money we have.
        :return:
        """
        total_cash = self._cash
        for key in self._stock_asset:
            asset = self._stock_asset[key]
            total_cash += asset.current_price*asset.number
        return total_cash