Esempio n. 1
0
def update_details(ib: IB, store: AbstractBaseStore,
                   keys: Optional[Union[str, List[str]]] = None) -> None:
    """
    Pull contract details from ib and update metadata in store.

    Args:
    ib: connected IB instance
    store: datastore instance, for which data will be updated
    keys (Optional): keys in datastore, for which data is to be updated,
                     if not given, update all keys
    """
    if keys is None:
        keys = store.keys()
    elif isinstance(keys, str):
        keys = [keys]

    contracts = {}
    for key in keys:
        try:
            contract = eval(store.read_metadata(key)['repr'])
        except TypeError:
            log.error(f'Metadata missing for {key}')
            continue
        contract.update(includeExpired=True)
        contracts[key] = contract
    ib.qualifyContracts(*contracts.values())
    details = {}
    for k, v in contracts.copy().items():
        try:
            details[k] = ib.reqContractDetails(v)[0]
        except IndexError:
            log.error(f'Contract unavailable: {k}')
            del contracts[k]

    # get commission levels
    order = MarketOrder('BUY', 1)
    commissions = {}
    for k, v in contracts.items():
        try:
            commissions[k] = ib.whatIfOrder(v, order).commission
        except AttributeError:
            log.error(f'Commission unavailable for: {k}')
            commissions[k] = np.nan

    for c, d in details.items():
        _d = {'name': d.longName,
              'min_tick': d.minTick,
              'commission': commissions[c]
              }
        store.write_metadata(c, _d)

    log.info('Data written to store.')
Esempio n. 2
0
class Live(IB):
    def __init__(self,
                 symbol,
                 temp,
                 client,
                 verbose=False,
                 notification=False):
        self.symbol = symbol
        instruments = pd.read_csv('instruments.csv').set_index('symbol')
        params = instruments.loc[self.symbol]
        self.market = str(params.market)
        self.exchange = str(params.exchange)
        self.temp = temp
        self.tick_size = float(params.tick_size)
        self.digits = int(params.digits)
        self.leverage = int(params.leverage)
        self.client = client
        self.verbose = verbose
        self.notification = notification
        self.ib = IB()
        print(self.ib.connect('127.0.0.1', 7497, client))
        self.get_contract()
        self.data = self.download_data(tempo=self.temp, duration='1 D')
        self.current_date()
        self.pool = pd.DataFrame(columns=[
            'date', 'id', 'type', 'lots', 'price', 'S/L', 'T/P', 'commission',
            'comment', 'profit'
        ])
        self.history = pd.DataFrame(columns=[
            'date', 'id', 'type', 'lots', 'price', 'S/L', 'T/P', 'commission',
            'comment', 'profit'
        ])
        self.pending = pd.DataFrame(columns=[
            'date', 'id', 'type', 'lots', 'price', 'S/L', 'T/P', 'commission',
            'comment', 'profit'
        ])
        self.position = 0
        self.number = 0

    def get_contract(self):
        if self.market == 'futures':
            expiration = self.ib.reqContractDetails(
                Future(self.symbol,
                       self.exchange))[0].contract.lastTradeDateOrContractMonth
            self.contract = Future(symbol=self.symbol,
                                   exchange=self.exchange,
                                   lastTradeDateOrContractMonth=expiration)
        elif self.market == 'forex':
            self.contract = Forex(self.symbol)
        elif self.market == 'stocks':
            self.contract = Stock(symbol=self.symbol,
                                  exchange=self.exchange,
                                  currency='USD')

    def download_data(self, tempo, duration):
        pr = (lambda mark: 'TRADES' if mark == 'futures' else
              ('TRADES' if mark == 'stocks' else 'MIDPOINT'))(self.market)
        historical = self.ib.reqHistoricalData(self.contract,
                                               endDateTime='',
                                               durationStr=duration,
                                               barSizeSetting=tempo,
                                               whatToShow=pr,
                                               useRTH=True,
                                               keepUpToDate=True)
        return historical

    def data_to_df(self, data):
        df = util.df(data)[['date', 'open', 'high', 'low', 'close',
                            'volume']].set_index('date')
        df.index = pd.to_datetime(df.index)
        return df

    def send_telegram_message(self, msg):
        '''Sends a telegram message
        '''
        requests.post(
            'https://api.telegram.org/bot804823606:AAFq-YMKr4hIjQ4N5M8GYCGa5w9JJ1kIunk/sendMessage',
            data={
                'chat_id': '@ranguito_channel',
                'text': msg
            })

    def current_date(self):
        self.date = datetime.now().strftime('%Y-%m-%d')
        self.weekday = datetime.now().weekday()
        self.hour = datetime.now().strftime('%H:%M:%S')

    def pool_check(self):
        '''Check pool trades'''
        if self.position == 0:
            self.pool = pd.DataFrame(columns=[
                'date', 'type', 'lots', 'price', 'S/L', 'T/P', 'commission',
                'comment', 'profit'
            ])

    def calculate_profit(self, type, price, lots):
        '''Calculates profit'''
        if type == 'BUY':
            profit = (lambda pos: 0
                      if pos >= 0 else (self.pool[self.pool.type == 'SELL'])[
                          'price'].iloc[0] - price)(self.position)
        else:
            profit = (lambda pos: 0 if pos <= 0 else price -
                      (self.pool[self.pool.type == 'BUY'])['price'].iloc[0])(
                          self.position)
        return profit * self.leverage * lots

    def order_values(self, order_id):
        price = 0
        commission = 0
        if len(self.ib.fills()) > 0:
            for trade in util.tree(self.ib.fills()):
                if ('OrderId' and 'clientId') in trade[1]['Execution']:
                    if ((nested_lookup('orderId', trade)[0] == order_id) and
                        (nested_lookup('clientId', trade)[0] == self.client)):
                        commission = nested_lookup('commission', trade)[0]
                        price = nested_lookup('price', trade)[0]
        return (price, commission)

    def order_send(self, type, lots, sl=0, tp=0, comment=''):
        market_order = MarketOrder(type, lots)
        #initial_margin, maintenance_margin = self.get_margins(market_order)
        self.ib.placeOrder(self.contract, market_order)
        id = market_order.orderId

        self.number += 1
        price = 0
        while price == 0:
            self.ib.sleep(1)
            price, commission = self.order_values(id)
        profit = self.calculate_profit(type, price, lots)
        trade = {
            'date': str(self.date) + ' ' + str(self.hour),
            'id': id,
            'type': type,
            'lots': lots,
            'price': price,
            'S/L': sl,
            'T/P': tp,
            'commission': commission,
            'comment': comment,
            'profit': profit
        }
        self.save_trade(trade)
        self.pool = pd.concat(
            [self.pool, pd.DataFrame(trade, index=[self.number])], sort=False)
        self.history = pd.concat(
            [self.history,
             pd.DataFrame(trade, index=[self.number])],
            sort=False)
        mult = (lambda dir: 1 if dir == 'BUY' else -1)(type)
        self.position += (mult * lots)
        self.pool_check()
        if self.verbose:
            print('%s %s | %sING %d units at %5.2f in %s' % (str(
                self.date), str(self.hour), type, lots, price, self.symbol))
        if self.notification:
            if self.position != 0:
                self.send_message_in(type, price, sl, tp, lots)
            else:
                self.send_message_out(type, price, lots, profit, commission,
                                      commission)

    def bracket_stop_order(self,
                           type,
                           lots,
                           entry_price,
                           sl=0,
                           tp=0,
                           comment=''):
        bracket_order = self.ib.bracketStopOrder(type, lots, entry_price, tp,
                                                 sl)
        #initial_margin, maintenance_margin = self.get_margins(bracket_order[0])
        for order in bracket_order:
            self.ib.placeOrder(self.contract, order)
        id_entry = bracket_order[0].orderId
        id_tp = bracket_order[1].orderId
        id_sl = bracket_order[2].orderId

        trade = {
            'date': str(self.date) + ' ' + str(self.hour),
            'id': id_entry,
            'type': bracket_order[0].action,
            'lots': lots,
            'price': entry_price,
            'S/L': sl,
            'T/P': tp,
            'commission': 0,
            'comment': comment,
            'profit': 0
        }
        self.pending = pd.concat(
            [self.pending, pd.DataFrame(trade, index=[id_entry])], sort=False)
        trade = {
            'date': str(self.date) + ' ' + str(self.hour),
            'id': id_tp,
            'type': bracket_order[1].action,
            'lots': lots,
            'price': tp,
            'S/L': 0,
            'T/P': 0,
            'commission': 0,
            'comment': comment,
            'profit': 0
        }
        self.pending = pd.concat(
            [self.pending, pd.DataFrame(trade, index=[id_entry])], sort=False)
        trade = {
            'date': str(self.date) + ' ' + str(self.hour),
            'id': id_sl,
            'type': bracket_order[2].action,
            'lots': lots,
            'price': sl,
            'S/L': 0,
            'T/P': 0,
            'commission': 0,
            'comment': comment,
            'profit': 0
        }
        self.pending = pd.concat(
            [self.pending, pd.DataFrame(trade, index=[id_entry])], sort=False)
        return (bracket_order[0], bracket_order[1], bracket_order[2])

    def pending_check(self, order):
        id = order.orderId
        if len(self.pending) > 0:
            price, commission = self.order_values(id)
            if price > 0:
                self.number += 1
                order_select = self.pending[self.pending.id == id]
                profit = self.calculate_profit(order_select.type.iloc[0],
                                               price,
                                               order_select.lots.iloc[0])
                trade = {
                    'date': str(self.date) + ' ' + str(self.hour),
                    'id': id,
                    'type': order_select.type.iloc[0],
                    'lots': order_select.lots.iloc[0],
                    'price': price,
                    'S/L': order_select['S/L'].iloc[0],
                    'T/P': order_select['T/P'].iloc[0],
                    'commission': commission,
                    'comment': '',
                    'profit': profit
                }
                self.save_trade(trade)
                self.pool = pd.concat(
                    [self.pool,
                     pd.DataFrame(trade, index=[self.number])],
                    sort=False)
                self.history = pd.concat(
                    [self.history,
                     pd.DataFrame(trade, index=[self.number])],
                    sort=False)
                mult = (lambda dir: 1
                        if dir == 'BUY' else -1)(order_select.type.iloc[0])
                self.position += (mult * order_select.lots.iloc[0])
                self.pool_check()
                if self.verbose:
                    print('%s %s | %sING %d units at %5.2f in %s' %
                          (str(self.date), str(
                              self.hour), order_select.type.iloc[0],
                           order_select.lots.iloc[0], price, self.symbol))
                if self.notification:
                    if self.position != 0:
                        self.send_message_in(order_select.type.iloc[0], price,
                                             order_select['S/L'].iloc[0],
                                             order_select['T/P'].iloc[0],
                                             order_select.lots.iloc[0])
                    else:
                        self.send_message_out(order_select.type.iloc[0], price,
                                              order_select.lots.iloc[0],
                                              profit, commission, commission)
                return True
            else:
                return False

    def get_margins(self, order):
        init_margin = float(
            self.ib.whatIfOrder(self.contract, order).initMarginChange)
        maint_margin = float(
            self.ib.whatIfOrder(self.contract, order).maintMarginChange)
        return (init_margin, maint_margin)

    def send_message_in(self, type, price_in, sl, tp, lots):
        msg_in = '%s Opened in %s \nPrice: %5.2f \nS/L: %5.2f \nT/P: %5.2f \nLots: %d \nAt: %s' % (
            type, self.symbol, price_in, sl, tp, lots, self.hour)
        self.send_telegram_message(msg_in)

    def send_message_out(self, type, price_out, lots, profit, comm_in,
                         comm_out):
        msg_out = '%s Closed in %s \nPrice: %5.2f \nProfit(USD): %5.2f \nCommissions(USD): %5.2f \nAt: %s' % \
                    (type, self.symbol, price_out, profit, (comm_in+comm_out),self.hour)
        self.send_telegram_message(msg_out)

    def save_trade(self, trade):
        if not path.exists('history_trades_%s.csv' % self.symbol):
            initial = pd.DataFrame(columns=[
                'date', 'id', 'type', 'lots', 'price', 'S/L', 'T/P',
                'commission', 'comment', 'profit'
            ]).set_index('date')
            initial.to_csv('history_trades_%s.csv' % self.symbol)
        history = pd.read_csv('history_trades_%s.csv' % self.symbol)
        trade = pd.DataFrame(trade, index=[0])
        history = pd.concat([history, trade], sort=False)
        history['net profit'] = history['profit'] - history['commission']
        history['accumulated profit'] = history['net profit'].cumsum()
        history['max profit'] = history['accumulated profit'].cummax()
        history.set_index('date').to_csv('history_trades_%s.csv' % self.symbol)