Esempio n. 1
0
def get_data_ib(instrument,
                start,
                resolution="1 min",
                blotter=None,
                output_path=None):
    """
    Downloads historical data from Interactive Brokers

    :Parameters:
        instrument : mixed
            IB contract tuple / string (same as that given to strategy)
        start : str
            Backtest start date (YYYY-MM-DD [HH:MM:SS[.MS])

    :Optional:
        resolution : str
            1 sec, 5 secs, 15 secs, 30 secs, 1 min (default), 2 mins, 3 mins, 5 mins, 15 mins, 30 mins, 1 hour, 1 day
        blotter : str
            Store MySQL server used by this Blotter (default is "auto detect")
        output_path : str
            Path to the location where the resulting CSV should be saved (default: ``None``)

    :Returns:
        data : pd.DataFrame
            Pandas DataFrame in a QTPyLib-compatible format and timezone
    """
    global _ib_history_downloaded

    # load blotter settings
    blotter_args = load_blotter_args(blotter,
                                     logger=logging.getLogger(__name__))

    # create contract string (no need for connection)
    ibConn = ezIBpy()
    ibConn.ibCallback = ibCallback

    if not ibConn.connected:
        ibConn.connect(clientId=0,
                       port=int(blotter_args['ibport']),
                       host=str(blotter_args['ibserver']))

    # generate a valid ib tuple
    instrument = tools.create_ib_tuple(instrument)
    contract_string = ibConn.contractString(instrument)
    contract = ibConn.createContract(instrument)

    ibConn.requestHistoricalData(contracts=[contract],
                                 data="TRADES",
                                 resolution=resolution,
                                 lookback=tools.ib_duration_str(start),
                                 rth=False)

    while not _ib_history_downloaded:
        time.sleep(.1)

    ibConn.disconnect()

    data = ibConn.historicalData[contract_string]
    data['datetime'] = data.index
    return prepare_data(instrument, data, output_path=output_path)
Esempio n. 2
0
def get_data_ib(instrument, start, resolution="1 min", blotter=None, output_path=None):
    """
    Downloads historical data from Interactive Brokers

    :Parameters:
        instrument : mixed
            IB contract tuple / string (same as that given to strategy)
        start : str
            Backtest start date (YYYY-MM-DD [HH:MM:SS[.MS])

    :Optional:
        resolution : str
            1 sec, 5 secs, 15 secs, 30 secs, 1 min (default), 2 mins, 3 mins, 5 mins, 15 mins, 30 mins, 1 hour, 1 day
        blotter : str
            Store MySQL server used by this Blotter (default is "auto detect")
        output_path : str
            Path to the location where the resulting CSV should be saved (default: ``None``)

    :Returns:
        data : pd.DataFrame
            Pandas DataFrame in a QTPyLib-compatible format and timezone
    """
    global _ib_history_downloaded

    # load blotter settings
    blotter_args = load_blotter_args(
        blotter, logger=logging.getLogger(__name__))

    # create contract string (no need for connection)
    ibConn = ezIBpy()
    ibConn.ibCallback = ibCallback

    if not ibConn.connected:
        ibConn.connect(clientId=0,
                       port=int(blotter_args['ibport']), host=str(blotter_args['ibserver']))

    # generate a valid ib tuple
    instrument = tools.create_ib_tuple(instrument)
    contract_string = ibConn.contractString(instrument)
    contract = ibConn.createContract(instrument)

    ibConn.requestHistoricalData(contracts=[contract],
                                 data="TRADES", resolution=resolution, lookback=tools.ib_duration_str(start), rth=False)

    while not _ib_history_downloaded:
        time.sleep(.1)

    ibConn.disconnect()

    data = ibConn.historicalData[contract_string]
    data['datetime'] = data.index
    return prepare_data(instrument, data, output_path=output_path)
Esempio n. 3
0
def ibCallback(caller, msg, **kwargs):
    print(caller)
    print(msg)
    #if caller == "handleTickGeneric":
    #    print("====Tick generic===")
    #    print(msg)
    #    print("====Tick generic===")

    #if caller == "handleTickPrice":
    #    print("====Tick price===")
    #    print(msg)
    #    print("====Tick price===")


# initialize ezIBpy
ibConn = ezibpy.ezIBpy()

# connect to IB (7496/7497 = TWS, 4001 = IBGateway)
ibConn.connect(clientId=111, host="localhost", port=4001)
ibConn.ibCallback = ibCallback

# create some contracts using dedicated methods
stk_contract0 = ibConn.createStockContract("AAPL")
stk_contract1 = ibConn.createStockContract("MSFT")
stk_contract2 = ibConn.createStockContract("TSLA")
stk_contract3 = ibConn.createStockContract("F")
stk_contract4 = ibConn.createStockContract("GE")
stk_contract5 = ibConn.createStockContract("F")
stk_contract6 = ibConn.createStockContract("QCOM")
stk_contract7 = ibConn.createStockContract("NFLX")
stk_contract8 = ibConn.createStockContract("GOOG")
Esempio n. 4
0
    def __init__(self, instruments, ibclient=998, ibport=4001, ibserver="localhost"):

        # detect running strategy
        self.strategy = str(self.__class__).split('.')[-1].split("'")[0]

        # initilize class logger
        self.log_broker = logging.getLogger(__name__)

        # default params (overrided in algo)
        self.timezone = "UTC"
        self.last_price = {}
        self.tick_window = 1000
        self.bar_window = 100

        # -----------------------------------
        # connect to IB
        self.ibclient = int(ibclient)
        self.ibport = int(ibport)
        self.ibserver = str(ibserver)

        self.ibConn = ezibpy.ezIBpy()
        self.ibConn.ibCallback = self.ibCallback
        self.ibConnect()

        # -----------------------------------
        # create contracts
        instrument_tuples_dict = {}
        for instrument in instruments:
            try:
                if isinstance(instrument, ezibpy.utils.Contract):
                    instrument = self.ibConn.contract_to_tuple(instrument)
                else:
                    instrument = tools.create_ib_tuple(instrument)
                contractString = self.ibConn.contractString(instrument)
                instrument_tuples_dict[contractString] = instrument
                self.ibConn.createContract(instrument)
            except Exception as e:
                pass

        self.instruments = instrument_tuples_dict
        self.symbols = list(self.instruments.keys())
        self.instrument_combos = {}

        # -----------------------------------
        # track orders & trades
        self.active_trades = {}
        self.trades = []

        # shortcut
        self.account = self.ibConn.account

        # use: self.orders.pending...
        self.orders = tools.make_object(
            by_tickerid=self.ibConn.orders,
            by_symbol=self.ibConn.symbol_orders,
            pending_ttls={},
            pending={},
            filled={},
            active={},
            history={},
            nextId=1,
            recent={}
        )

        # -----------------------------------
        self.dbcurr = None
        self.dbconn = None

        # -----------------------------------
        # assign default vals if not propogated from algo
        if not hasattr(self, 'backtest'):
            self.backtest = False

        if not hasattr(self, 'sms_numbers'):
            self.sms_numbers = []

        if not hasattr(self, 'trade_log_dir'):
            self.trade_log_dir = None

        if not hasattr(self, 'blotter_name'):
            self.blotter_name = None

        # -----------------------------------
        # load blotter settings
        self.blotter_args = load_blotter_args(
            self.blotter_name, logger=self.log_broker)
        self.blotter = Blotter(**self.blotter_args)

        # connect to mysql using blotter's settings
        if not self.blotter_args['dbskip']:
            self.dbconn = pymysql.connect(
                host=str(self.blotter_args['dbhost']),
                port=int(self.blotter_args['dbport']),
                user=str(self.blotter_args['dbuser']),
                passwd=str(self.blotter_args['dbpass']),
                db=str(self.blotter_args['dbname']),
                autocommit=True
            )
            self.dbcurr = self.dbconn.cursor()

        # -----------------------------------
        # do stuff on exit
        atexit.register(self._on_exit)
Esempio n. 5
0
    def run(self):
        """Starts the blotter

        Connects to the TWS/GW, processes and logs market data,
        and broadcast it over TCP via ZeroMQ (which algo subscribe to)
        """

        self._check_unique_blotter()

        # connect to mysql
        self.mysql_connect()

        self.context = zmq.Context(zmq.REP)
        self.socket = self.context.socket(zmq.PUB)
        self.socket.bind("tcp://*:" + str(self.args['zmqport']))

        db_modified = 0
        contracts = []
        prev_contracts = []
        first_run = True

        logging.info("Connecting to Interactive Brokers...")
        self.ibConn = ezIBpy()
        self.ibConn.ibCallback = self.ibCallback

        while not self.ibConn.connected:
            self.ibConn.connect(clientId=int(self.args['ibclient']),
                                port=int(self.args['ibport']),
                                host=str(self.args['ibserver']))
            time.sleep(1)
            if not self.ibConn.connected:
                print('*', end="", flush=True)
        logging.info("Connection established...")

        try:
            while True:

                if not os.path.exists(self.args['symbols']):
                    pd.DataFrame(columns=[
                        'symbol', 'sec_type', 'exchange', 'currency', 'expiry',
                        'strike', 'opt_type'
                    ]).to_csv(self.args['symbols'], header=True, index=False)
                    tools.chmod(self.args['symbols'])
                else:
                    time.sleep(0.1)

                    # read db properties
                    db_data = os.stat(self.args['symbols'])
                    db_size = db_data.st_size
                    db_last_modified = db_data.st_mtime

                    # empty file
                    if db_size == 0:
                        if len(prev_contracts) > 0:
                            logging.info('Cancel market data...')
                            self.ibConn.cancelMarketData()
                            time.sleep(0.1)
                            prev_contracts = []
                        continue

                    # modified?
                    if (first_run == False) & (db_last_modified
                                               == db_modified):
                        continue

                    # continue...
                    db_modified = db_last_modified

                    # read contructs db
                    df = pd.read_csv(self.args['symbols'], header=0)
                    if len(df.index) == 0:
                        continue

                    # removed expired
                    df = df[(
                        (df['expiry'] < 1000000) &
                        (df['expiry'] >= int(datetime.now().strftime('%Y%m'))))
                            | ((df['expiry'] >= 1000000) &
                               (df['expiry'] >= int(datetime.now(
                               ).strftime('%Y%m%d')))) | isnan(df['expiry'])]
                    df.fillna("", inplace=True)
                    df.to_csv(self.args['symbols'], header=True, index=False)
                    tools.chmod(self.args['symbols'])

                    df = df[df['symbol'].str.contains("#") ==
                            False]  # ignore commentee
                    contracts = [tuple(x) for x in df.values]

                    if first_run:
                        first_run = False

                    else:
                        if contracts != prev_contracts:
                            # cancel market data for removed contracts
                            for contract in prev_contracts:
                                if contract not in contracts:
                                    self.ibConn.cancelMarketData(
                                        self.ibConn.createContract(contract))
                                    time.sleep(0.1)
                                    contract_string = self.ibConn.contractString(
                                        contract).split('_')[0]
                                    logging.info('Contract Removed [' +
                                                 contract_string + ']')

                    # request market data
                    for contract in contracts:
                        if contract not in prev_contracts:
                            self.ibConn.requestMarketData(
                                self.ibConn.createContract(contract))
                            time.sleep(0.1)
                            contract_string = self.ibConn.contractString(
                                contract).split('_')[0]
                            logging.info('Contract Added [' + contract_string +
                                         ']')

                    # update latest contracts
                    prev_contracts = contracts

                time.sleep(2)

        except (KeyboardInterrupt, SystemExit):
            print("\n\n>>> Interrupted with Ctrl-c...")
            sys.exit(1)
Esempio n. 6
0
import sys
import shlex
import ezibpy
import time
import prettytable

SHELL_STATUS_RUN = 1
SHELL_STATUS_STOP = 0

tickers_ = []
# initialize ezIBpy
ibConn_ = ezibpy.ezIBpy()


def ibCallback(caller, msg, table=None, **kwargs):
    if table is None:
        return
    if caller in ["handleAccount", "handlePortfolio"]:
        print("\n", caller)
        prettytable.pprint_table(sys.stdout, table)


def initConnection():
    global ibConn_
    # connect to IB (7496/7497 = TWS, 4001 = IBGateway)
    ibConn_.accountCode = 'xxxxxxx'
    ibConn_.connect(clientId=100, host="localhost", port=7496)


def initCallback():
    global ibConn_
Esempio n. 7
0
def prepare_data(instrument, data, output_path=None,
                 index=None, colsmap=None, kind="BAR", resample="1T"):
    """
    Converts given DataFrame to a QTPyLib-compatible format and timezone

    :Parameters:
        instrument : mixed
            IB contract tuple / string (same as that given to strategy)
        data : pd.DataFrame
            Pandas DataDrame with that instrument's market data
        output_path : str
            Path to where the resulting CSV should be saved (optional)
        index : pd.Series
            Pandas Series that will be used for df's index (optioanl)
        colsmap : dict
            Dict for mapping df's columns to those used by QTPyLib
            (default assumes same naming convention as QTPyLib's)
        kind : str
            Is this ``BAR`` or ``TICK`` data
        resample : str
            Pandas resolution (defaults to 1min/1T)

    :Returns:
        data : pd.DataFrame
            Pandas DataFrame in a QTPyLib-compatible format and timezone
    """

    global _TICKS_COLSMAP, _BARS_COLSMAP

    # work on copy
    df = data.copy()

    # ezibpy's csv?
    if set(df.columns) == set([
            'datetime', 'C', 'H', 'L', 'O', 'OI', 'V', 'WAP']):
        df.rename(columns={
            'datetime': 'datetime',
            'O': 'open',
            'H': 'high',
            'L': 'low',
            'C': 'close',
            'OI': 'volume',
        }, inplace=True)
        df.index = pd.to_datetime(df['datetime'])
        df.index = df.index.tz_localize(tools.get_timezone()).tz_convert("UTC")
        index = None

    # lower case columns
    df.columns = map(str.lower, df.columns)

    # set index
    if index is None:
        index = df.index

    # set defaults columns
    if not isinstance(colsmap, dict):
        colsmap = {}

    _colsmap = _TICKS_COLSMAP if kind == "TICK" else _BARS_COLSMAP
    for el in _colsmap:
        if el not in colsmap:
            colsmap[el] = _colsmap[el]

    # generate a valid ib tuple
    instrument = tools.create_ib_tuple(instrument)

    # create contract string (no need for connection)
    ibConn = ezIBpy()
    contract_string = ibConn.contractString(instrument)
    asset_class = tools.gen_asset_class(contract_string)
    symbol_group = tools.gen_symbol_group(contract_string)

    # add symbol data
    df.loc[:, 'symbol'] = contract_string
    df.loc[:, 'symbol_group'] = symbol_group
    df.loc[:, 'asset_class'] = asset_class

    # validate columns
    valid_cols = validate_columns(df, kind)
    if not valid_cols:
        raise ValueError('Invalid Column list')

    # rename columns to map
    df.rename(columns=colsmap, inplace=True)

    # force option columns on options
    if asset_class == "OPT":
        df = tools.force_options_columns(df)

    # remove all other columns
    known_cols = list(colsmap.values()) + \
        ['symbol', 'symbol_group', 'asset_class', 'expiry']
    for col in df.columns:
        if col not in known_cols:
            df.drop(col, axis=1, inplace=True)

    # set UTC index
    df.index = pd.to_datetime(index)
    df = tools.set_timezone(df, "UTC")
    df.index.rename("datetime", inplace=True)

    # resample
    if resample and kind == "BAR":
        df = tools.resample(df, resolution=resample, tz="UTC")

    # add expiry
    df.loc[:, 'expiry'] = np.nan
    if asset_class in ("FUT", "OPT", "FOP"):
        df.loc[:, 'expiry'] = contract_expiry_from_symbol(contract_string)

    # save csv
    if output_path is not None:
        output_path = output_path[
            :-1] if output_path.endswith('/') else output_path
        df.to_csv("%s/%s.%s.csv" % (output_path, contract_string, kind))

    # return df
    return df
Esempio n. 8
0
    def __init__(self,
                 instruments,
                 ibclient=999,
                 ibport=4001,
                 ibserver="localhost",
                 **kwargs):

        # -----------------------------------
        # detect running strategy
        self.strategy = str(self.__class__).split('.')[-1].split("'")[0]

        # -----------------------------------
        # connect to IB
        self.ibclient = int(ibclient)
        self.ibport = int(ibport)
        self.ibserver = str(ibserver)

        self.ibConn = ezibpy.ezIBpy()
        self.ibConn.ibCallback = self.ibCallback
        self.ibConnect()

        # -----------------------------------
        # create contracts
        instrument_tuples_dict = {}
        for instrument in instruments:
            try:
                # signgle string
                if isinstance(instrument, str):
                    instrument = instrument.upper()

                    if "FUT." not in instrument:
                        # symbol stock
                        instrument = (instrument, "STK", "SMART", "USD", "",
                                      0.0, "")

                    else:
                        # future contract
                        try:
                            symdata = instrument.split(".")

                            # is this a CME future?
                            if symdata[
                                    1] not in futures.futures_contracts.keys():
                                raise ValueError(
                                    "Un-supported symbol. Please use full contract tuple."
                                )

                            # auto get contract details
                            spec = futures.get_ib_futures(symdata[1])
                            if not isinstance(spec, dict):
                                raise ValueError("Un-parsable contract tuple")

                            # expiry specified?
                            if len(symdata) == 3 and symdata[2] != '':
                                expiry = symdata[2]
                            else:
                                # default to most active
                                expiry = futures.get_active_contract(
                                    symdata[1])

                            instrument = (spec['symbol'].upper(), "FUT",
                                          spec['exchange'].upper(),
                                          spec['currency'].upper(),
                                          int(expiry), 0.0, "")

                        except:
                            raise ValueError("Un-parsable contract tuple")

                # tuples without strike/right
                elif len(instrument) <= 7:
                    instrument_list = list(instrument)
                    if len(instrument_list) < 3:
                        instrument_list.append("SMART")
                    if len(instrument_list) < 4:
                        instrument_list.append("USD")
                    if len(instrument_list) < 5:
                        instrument_list.append("")
                    if len(instrument_list) < 6:
                        instrument_list.append(0.0)
                    if len(instrument_list) < 7:
                        instrument_list.append("")

                    try:
                        instrument_list[4] = int(instrument_list[4])
                    except:
                        pass

                    instrument_list[5] = 0. if isinstance(instrument_list[5], str) \
                        else float(instrument_list[5])

                    instrument = tuple(instrument_list)

                contractString = self.ibConn.contractString(instrument)
                instrument_tuples_dict[contractString] = instrument
                self.ibConn.createContract(instrument)
            except:
                pass

        self.instruments = instrument_tuples_dict
        self.symbols = list(self.instruments.keys())

        # -----------------------------------
        # track orders & trades
        self.active_trades = {}
        self.trades = []

        # shortcut
        self.account = self.ibConn.account

        # use: self.orders.pending...
        self.orders = tools.make_object(by_tickerid=self.ibConn.orders,
                                        by_symbol=self.ibConn.symbol_orders,
                                        pending_ttls={},
                                        pending={},
                                        filled={},
                                        active={},
                                        history={},
                                        nextId=1,
                                        recent={})

        # -----------------------------------
        self.dbcurr = None
        self.dbconn = None

        # -----------------------------------
        # assign default vals if not propogated from algo
        if not hasattr(self, 'backtest'):
            self.backtest = False

        if not hasattr(self, 'sms_numbers'):
            self.sms_numbers = []

        if not hasattr(self, 'trade_log_dir'):
            self.trade_log_dir = None

        if not hasattr(self, 'blotter_name'):
            self.blotter_name = None

        # -----------------------------------
        # load blotter settings
        self.blotter_args = {}
        self.load_blotter_args(self.blotter_name)

        # -----------------------------------
        # do stuff on exit
        atexit.register(self._on_exit)
Esempio n. 9
0
 def connect_to_tws(self):
     self.ibConn = ezibpy.ezIBpy()
     self.ibConn.connect(clientId=self.client,
                         host=self.host,
                         port=self.port)
Esempio n. 10
0
def prepare_data(instrument, data, output_path=None, index=None, colsmap=None, kind="BAR"):
    """
    Converts given DataFrame to a QTPyLib-compatible format and timezone

    :Parameters:
        instrument : mixed
            IB contract tuple / string (same as that given to strategy)
        data : pd.DataFrame
            Pandas DataDrame with that instrument's market data
        output_path : str
            Path to the location where the resulting CSV should be saved (default: ``None``)
        index : pd.Series
            Pandas Series that will be used for df's index (default is to use df.index)
        colsmap : dict
            Dict for mapping df's columns to those used by QTPyLib (default assumes same naming convention as QTPyLib's)
        kind : str
            Is this ``BAR`` or ``TICK`` data

    :Returns:
        data : pd.DataFrame
            Pandas DataFrame in a QTPyLib-compatible format and timezone
    """

    global _bars_colsmap, _ticks_colsmap

    # work on copy
    df = data.copy()

    # ezibpy's csv?
    if set(df.columns) == set(['datetime', 'C', 'H', 'L', 'O', 'OI', 'V', 'WAP']):
        df.rename(columns={
            'datetime': 'datetime',
            'O': 'open',
            'H': 'high',
            'L': 'low',
            'C': 'close',
            'OI': 'volume',
        }, inplace=True)
        df.index = pd.to_datetime(df['datetime'])
        df.index = df.index.tz_localize(tools.get_timezone()).tz_convert("UTC")
        index = None

    # set index
    if index is None:
        index = df.index

    # set defaults columns
    if not isinstance(colsmap, dict):
        colsmap = {}

    _colsmap = _ticks_colsmap if kind == "TICK" else _bars_colsmap
    for el in _colsmap:
        if el not in colsmap:
            colsmap[el] = _colsmap[el]

    # generate a valid ib tuple
    instrument = tools.create_ib_tuple(instrument)

    # create contract string (no need for connection)
    ibConn = ezIBpy()
    contract_string = ibConn.contractString(instrument)
    asset_class = tools.gen_asset_class(contract_string)
    symbol_group = tools.gen_symbol_group(contract_string)

    # add symbol data
    df.loc[:, 'symbol'] = contract_string
    df.loc[:, 'symbol_group'] = symbol_group
    df.loc[:, 'asset_class'] = asset_class

    # validate columns
    valid_cols = validate_columns(df, kind)
    if not valid_cols:
        raise ValueError('Invalid Column list')

    # rename columns to map
    df.rename(columns=colsmap, inplace=True)

    # force option columns on options
    if asset_class == "OPT":
        df = tools.force_options_columns(df)

    # remove all other columns
    known_cols = list(colsmap.values()) + ['symbol','symbol_group','asset_class','expiry']
    for col in df.columns:
        if col not in known_cols:
            df.drop(col, axis=1, inplace=True)

    # set UTC index
    df.index = pd.to_datetime(index)
    df = tools.set_timezone(df, "UTC")
    df.index.rename("datetime", inplace=True)

    # add expiry
    df.loc[:, 'expiry'] = np.nan
    if asset_class in ("FUT", "OPT", "FOP"):
        df.loc[:, 'expiry'] = contract_expiry_from_symbol(contract_string)

    # save csv
    if output_path is not None:
        output_path = output_path[
            :-1] if output_path.endswith('/') else output_path
        df.to_csv("%s/%s.%s.csv" % (output_path, contract_string, kind))

    # return df
    return df
Esempio n. 11
0
class IBMarket(object):
    conn = ezibpy.ezIBpy()
    conn.connect(clientId=101, host="localhost", port=4001)
    market_data_available = {}

    # define custom callback
    def ibCallback(self, caller, msg, **kwargs):
        #print(caller)
        #print(msg)
        try:
            if caller == "handleHistoricalData":
                completed = kwargs.get('completed')
                if completed == True:
                    symbol = IBMarket.conn.contracts[msg.reqId].m_symbol
                    print("Historical data downloaded for %s" % symbol)
                    IBMarket.market_data_available[symbol] = True
        except:
            print("ERROR HANDLE CALLBACK")

    def __init__(self, rth=False):
        self.period = None
        self.data = None
        self.rth = rth

        IBMarket.conn.ibCallback = self.ibCallback

    def isPostClose(self, timenow):
        weekday = datetime.today().weekday()
        postclosetime = datetime.now().replace(hour=20, minute=00)
        closetime = datetime.now().replace(hour=16, minute=00)

        if weekday < 5 and timenow > closetime and timenow < postclosetime:
            ispostclose = True
        else:
            ispostclose = False

        return ispostclose

    def isPreOpen(self, timenow):
        weekday = datetime.today().weekday()
        preopentime = datetime.now().replace(hour=4, minute=00)
        opentime = datetime.now().replace(hour=9, minute=30)

        if weekday < 5 and timenow < opentime and timenow > preopentime:
            ispreopen = True
        else:
            ispreopen = False

        return ispreopen

    def isOpen(self, timenow):
        weekday = datetime.today().weekday()
        opentime = datetime.now().replace(hour=9, minute=30)
        closetime = datetime.now().replace(hour=16, minute=00)

        if weekday < 5 and timenow > opentime and timenow < closetime:
            isopen = True
        else:
            isopen = False

        return isopen

    def getDailyData(self, symbol, since, debug=False):
        #try:
        print("GET IBKR INTRADAY DATA")
        now = datetime.now()

        print("CREATE CONTRACT FOR %s" % symbol)
        contract = IBMarket.conn.createStockContract(symbol)

        dirname = os.path.dirname(__file__)
        filename = "data/daily/" + symbol + "_" + now.strftime(
            "%Y_%m_%d") + "_1_day.csv"

        if os.path.isfile(filename) == True:
            os.remove(filename)

        print("REQUEST HISTORICAL DATA FOR %s SINCE %s" % (symbol, since))
        IBMarket.market_data_available[symbol] = False
        IBMarket.conn.requestHistoricalData(contract,
                                            rth=self.rth,
                                            resolution="1 day",
                                            lookback="12 M",
                                            csv_path='data/daily/')

        print("WAIT FOR DATA...")
        while IBMarket.market_data_available[symbol] == False:
            time.sleep(5)
        IBMarket.market_data_available[symbol] = False

        print("RENAME CSV FILE TO %s" % filename)
        os.rename("data/daily/" + symbol + ".csv", filename)

        print("READ CSV FILE:%s" % filename)
        self.data = pd.read_csv(filename,
                                index_col='datetime',
                                parse_dates=True)
        self.data = self.data.sort_index()
        if debug:
            print("===VALUES===")
            print(self.data)

        print("===CALCULATE ALL TA===")
        self.data = ta.utils.dropna(self.data)
        self.data['sma20'] = SMAIndicator(close=self.data['C'],
                                          n=20,
                                          fillna=True).sma_indicator()
        self.data['sma50'] = SMAIndicator(close=self.data['C'],
                                          n=50,
                                          fillna=True).sma_indicator()
        self.data['sma100'] = SMAIndicator(close=self.data['C'],
                                           n=100,
                                           fillna=True).sma_indicator()
        self.data['sma200'] = SMAIndicator(close=self.data['C'],
                                           n=200,
                                           fillna=True).sma_indicator()

        self.data['ema9'] = EMAIndicator(close=self.data['C'],
                                         n=9,
                                         fillna=True).ema_indicator()
        self.data['ema20'] = EMAIndicator(close=self.data['C'],
                                          n=20,
                                          fillna=True).ema_indicator()

        self.data = ta.add_all_ta_features(self.data,
                                           open="O",
                                           high="H",
                                           low="L",
                                           close="C",
                                           volume="V",
                                           fillna=True)

        self.data = self.data.loc[self.data.index >= since]

        print("===CALCULATE DOJI===")
        candle_names = talib.get_function_groups()['Pattern Recognition']
        included_items = ('CDLDOJI', 'CDLHAMMER', 'CDLEVENINGSTAR',
                          'CDLHANGINGMAN', 'CDLSHOOTINGSTAR')
        candle_names = [
            candle for candle in candle_names if candle in included_items
        ]

        for candle in candle_names:
            self.data[candle] = getattr(talib,
                                        candle)(self.data['O'], self.data['H'],
                                                self.data['L'], self.data['C'])

        if debug:
            print("===VALUES===")
            print(self.data[[
                'C', 'V', 'WAP', 'sma20', 'sma50', 'sma100', 'sma200',
                'momentum_rsi', 'trend_cci', 'momentum_stoch_signal',
                'trend_adx'
            ]])

        #except:
        #	print("ERROR GETTING MARKET DATA")
        #	time.sleep(60)
        #	self.data = None

        #30 request / 10 mins -> need to wait 20 secs
        time.sleep(20)
        return self.data

    def getIntraDayData(self, symbol, since, period, live=False, debug=False):
        #try:
        print("GET IBKR INTRADAY DATA")
        if live == True:
            lookback = int(period * 1600 / 60 / 24)
        else:
            dtime = datetime.now() - datetime.strptime(since, '%Y-%m-%d')
            #lookback = dtime.total_seconds() / 60 / 60 / 24
            lookback = 7

        now = datetime.now()

        print("CREATE CONTRACT FOR %s" % symbol)
        contract = IBMarket.conn.createStockContract(symbol)

        dirname = os.path.dirname(__file__)
        filename = "data/intraday/" + symbol + "_" + now.strftime(
            "%Y_%m_%d") + "_" + str(period) + "_min.csv"

        if os.path.isfile(filename) == True:
            os.remove(filename)

        print(
            "REQUEST HISTORICAL DATA FOR %s, LOOKBACK %d DAYS, SINCE %s, RTH:%d"
            % (symbol, lookback, since, self.rth))
        IBMarket.market_data_available[symbol] = False
        IBMarket.conn.requestHistoricalData(contract,
                                            rth=self.rth,
                                            resolution=str(period) + " mins",
                                            lookback=str(lookback) + " D",
                                            csv_path='data/intraday/')

        print("WAIT FOR DATA...")
        while IBMarket.market_data_available[symbol] == False:
            time.sleep(5)
        IBMarket.market_data_available[symbol] = False

        print("RENAME CSV FILE")
        os.rename("data/intraday/" + symbol + ".csv", filename)

        print("READ CSV DATA")
        self.data = pd.read_csv(filename,
                                index_col='datetime',
                                parse_dates=True)
        self.data = self.data.sort_index()
        self.data = self.data[:-1]
        if debug:
            print("===VALUES===")
            print(self.data)

        print("===CALCULATE SMA===")
        # add trend indicator.
        #self.data['sma20'] = self.data['C'].rolling(20, min_periods=20).mean()
        #self.data['sma50'] = self.data['C'].rolling(50, min_periods=50).mean()
        #self.data['sma100'] = self.data['C'].rolling(100, min_periods=100).mean()
        #self.data['sma200'] = self.data['C'].rolling(200, min_periods=200).mean()

        print("===CALCULATE ALL TA===")
        self.data = ta.utils.dropna(self.data)
        self.data['sma20'] = SMAIndicator(close=self.data['C'],
                                          n=20,
                                          fillna=True).sma_indicator()
        self.data['sma50'] = SMAIndicator(close=self.data['C'],
                                          n=50,
                                          fillna=True).sma_indicator()
        self.data['sma100'] = SMAIndicator(close=self.data['C'],
                                           n=100,
                                           fillna=True).sma_indicator()
        self.data['sma200'] = SMAIndicator(close=self.data['C'],
                                           n=200,
                                           fillna=True).sma_indicator()

        self.data['ema9'] = EMAIndicator(close=self.data['C'],
                                         n=9,
                                         fillna=True).ema_indicator()
        self.data['ema20'] = EMAIndicator(close=self.data['C'],
                                          n=20,
                                          fillna=True).ema_indicator()

        self.data = ta.add_all_ta_features(self.data,
                                           open="O",
                                           high="H",
                                           low="L",
                                           close="C",
                                           volume="V",
                                           fillna=True)

        self.data['mvwap'] = self.data['volume_vwap'].rolling(
            14, min_periods=14).mean()
        self.data = self.data.loc[self.data.index >= since]

        print("===CALCULATE DOJI===")
        candle_names = talib.get_function_groups()['Pattern Recognition']
        if debug:
            print(candle_names)

        included_items = ('CDLDOJI', 'CDLHAMMER', 'CDLEVENINGSTAR',
                          'CDLHANGINGMAN', 'CDLSHOOTINGSTAR')
        candle_names = [
            candle for candle in candle_names if candle in included_items
        ]

        for candle in candle_names:
            self.data[candle] = getattr(talib,
                                        candle)(self.data['O'], self.data['H'],
                                                self.data['L'], self.data['C'])

        if debug:
            print("===VALUES===")
            print(self.data)

        #except:
        #    print("ERROR GETTING MARKET DATA")
        #    time.sleep(60)
        #    self.data = None

        return self.data
Esempio n. 12
0
class IBBroker(object):
    conn = ezibpy.ezIBpy()
    conn.connect(clientId=100, host="localhost", port=4001)
    conn.requestPositionUpdates(subscribe=True)
    conn.requestAccountUpdates(subscribe=True)
    totalbudget = 0
    totalinvested = 0

    def __init__(self, totalbudget, quota, logger):
        IBBroker.totalbudget = totalbudget
        self.quota = quota
        self.cash = quota
        self.invested = 0
        self.profit = 0
        self.perf = 0
        self.mylogger = logger
        self.value = 0
        self.buypending = False
        self.sellpending = False

        print("[IBK] quota %.3f, cash %.3f" % (self.quota, self.cash))

    def buy_short_shares(self, stock, nb_shares, price=None):
        return self.sell_shares(stock, nb_shares, price)

    def sell_short_shares(self, stock, nb_shares, price=None):
        return self.buy_shares(stock, nb_shares, price)

    def buy_shares(self, stock, nb_shares, price=None):
        nb_shares = math.floor(nb_shares)
        if nb_shares == 0:
            return -1

        if IBBroker.totalinvested + nb_shares * stock.close > IBBroker.totalbudget:
            self.mylogger.logger.debug("OVER BUDGET, CANNOT BUY %s" %
                                       stock.symbol)
            return -1

        if self.cash < nb_shares * stock.close:
            self.mylogger.logger.debug(
                "NOT ENOUGH CASH LEFT %.3f$ TO BUY %.3f$" %
                (self.cash, nb_shares * stock.close))
            return -1

        if stock.totalbuysize * stock.avgbuyprice > self.quota:
            self.mylogger.logger.debug(
                "HAVE %.3f$, ABOVE QUOTA OF %.3f$" %
                (stock.totalbuysize * stock.avgbuyprice, self.quota))
            return -1

        if self.buypending == True and self.buyorder['status'] != "FILLED":
            self.mylogger.logger.debug("BUY ORDER PENDING")
            return -1

        self.buypending = False
        contract = IBBroker.conn.createStockContract(stock.symbol)
        if price is None:
            self.buyorder = IBBroker.conn.createOrder(quantity=nb_shares,
                                                      rth=True)
        else:
            self.buyorder = IBBroker.conn.createOrder(quantity=nb_shares,
                                                      price=price,
                                                      rth=True)
        id = IBBroker.conn.placeOrder(contract, self.buyorder)
        self.mylogger.logger.debug(
            "%s [%s] IBK ORDER ID:%d, BUY %d SHARES @ %.3f$ OF %s" %
            (datetime.now(), stock.symbol, id, nb_shares, stock.close,
             stock.symbol))
        self.mylogger.tradebook.debug(
            "%s [%s] IBK ORDER ID:%d, BUY %d SHARES @ %.3f$ OF %s" %
            (datetime.now(), stock.symbol, id, nb_shares, stock.close,
             stock.symbol))
        time.sleep(5)
        self.buypending = True

        result = stock.buy(nb_shares)
        self.cash -= stock.close * nb_shares
        self.invested = stock.avgbuyprice * stock.totalbuysize
        self.calculate_profit(stock)
        IBBroker.totalinvested += self.invested
        return result

    def sell_shares(self, stock, nb_shares, price=None):
        nb_shares = math.floor(nb_shares)
        if nb_shares == 0:
            return -1

        if self.invested < nb_shares * stock.avgbuyprice:
            return -1

        if self.sellpending == True and self.sellorder['status'] != "FILLED":
            self.mylogger.logger.debug("SELL ORDER PENDING")
            return -1

        self.sellpending = False
        contract = IBBroker.conn.createStockContract(stock.symbol)
        if price is None:
            self.sellorder = IBBroker.conn.createOrder(quantity=nb_shares * -1,
                                                       rth=True)
        else:
            self.sellorder = IBBroker.conn.createOrder(quantity=nb_shares * -1,
                                                       price=price,
                                                       rth=True)
        id = IBBroker.conn.placeOrder(contract, self.sellorder)
        self.mylogger.logger.debug(
            "%s [%s] ORDER ID: %d, SELL %d SHARES @ %.3f$ OF %s" %
            (datetime.now(), stock.symbol, id, nb_shares, stock.close,
             stock.symbol))
        self.mylogger.tradebook.debug(
            "%s [%s] ORDER ID: %d, SELL %d SHARES @ %.3f$ OF %s" %
            (datetime.now(), stock.symbol, id, nb_shares, stock.close,
             stock.symbol))
        time.sleep(5)
        self.sellpending = True

        result = stock.sell(nb_shares)
        self.cash += stock.close * nb_shares
        self.invested = stock.avgbuyprice * stock.totalbuysize
        self.calculate_profit(stock)
        IBBroker.totalinvested -= self.invested
        return result

    def calculate_profit(self, stock):
        self.profit = (self.cash + self.invested) - self.quota
        self.value = stock.totalbuysize * stock.close
        self.unrzprofit = self.value - self.invested
        self.perf = self.profit / self.quota * 100

    def print_balance(self, stock):
        self.calculate_profit(stock)
        self.mylogger.logger.debug(
            "%s [%6s] #TRANSAC = %d , CASH = %8.2f$, INVESTED = %8.2f$, VALUE = %8.2f RLZ PROFIT = %8.2f$, UNRLZ PROFIT = %8.2f$, PERF = %8.2f%%"
            % (stock.tstamp, stock.symbol, stock.transaction, self.cash,
               self.invested, self.value, self.profit, self.unrzprofit,
               self.perf))