def header_print(client):
    '''
    Print Local Time, Timezone and Account Balance Info
    '''
    t_local = time.time() * 1000
    print('\n' + barstr(text="", space_size=0))
    print(barstr(text='IG Server Connecting Session Info'))
    print('\n\n\tDemo Server: %s' % str(demo))
    print('\tLocal Time at Start: %s, \n\tServer Timezone Offset : UTC%+d' %
          (timestr(t_local), resp['timezoneOffset']))
    print('\n\tAccount Balance info at Start:')
    try:
        accounts = client.account_details()['accounts']
        for n in range(len(accounts)):
            info = {
                str(key): str(value)
                for key, value in iter(accounts[0].items())
            }
            balance = {
                str(key): str(value)
                for key, value in iter(accounts[0]['balance'].items())
            }
            print('\tAccount #{}:'.format(n))
            print(
                "\tId : {accountId:<} \tType : {accountType:<} \tStatus : {status:<} \tCurrency : {currency:<}"
                .format(**info))
            print(
                "\tBalance \tTotal : {balance:<} \tAvailable : {available:<}".
                format(**balance))
        print('\n')
    except Exception:
        print('\tFAIL to connect to client.balance. \n')
Beispiel #2
0
    def close_stream(self, on_close=None):
        '''
        Call self.unsubcribe() and self.disconnect()
        '''
        self.unsubcribe()
        self.disconnect()
        if bool(on_close):
            on_close()
        else:
            print('\n' + barstr(text='Close Data Streaming') + '\n')


###%%%
Beispiel #3
0
 def open_stream(self, on_open=None):
     '''
     Call self.connect() and self.subcribe()
     Create message tracker --> self._prevResp : dict
     '''
     conn_status = self.connect()
     sub_status = self.subcribe()
     self._prevResp = {}
     for item in self.subscriptions['item_names']:
         self._prevResp[item] = {}
         for field in self.subscriptions['field_names']:
             self._prevResp[item][field] = None
     if conn_status == 'OK' and sub_status == 'OK':
         if bool(on_open):
             on_open()
         else:
             print('\n' + barstr(text='Start Data Streaming') + '\n')
     else:
         print('\tERROR ~ \tConnect : ', conn_status, 'Subcribe : ',
               sub_status)
demo = True
if demo:
    # demo IG
    username = ''
    password = ''
    apikey = ''
else:
    # IG
    username = ''
    password = ''
    apikey = ''
"""Client to connect to IG Server"""
client = Client(username=username,
                password=password,
                api_key=apikey,
                demo=demo)
resp = client.create_session(encrypted=True)

header_print(client)
"""Multi-threading function. One can call data_stream() directly"""
t1 = threading.Thread(target=data_stream)
t1.setDaemon(True)
t1.start()
t1.join()

print('\n\tLocal Time at Close: %s \n' % timestr(time.time() * 1000))
print(
    barstr(text='Elapsed time = {} seconds'.format(
        round(time.time() - start_time, 2))))
print(barstr(text="", space_size=0))
os._exit(1)
def main(args):
    start_time = time.time()
    testnet = True
    filename = str(int(time.time()))
    if testnet:
        # Testnet
        # "key": "d782f0d42dcf016c32fd56a96d01bb0e120f78802d9de378cdb9fde2b6c841e8",
        #"secret": "1ec873bf3137868a9e12e57e8e19cfa5a3a38cec403b741d2f7cd881c51bfd72"
        apikey = 'd782f0d42dcf016c32fd56a96d01bb0e120f78802d9de378cdb9fde2b6c841e8'  ### INSERT your api key here ###
        scrkey = '1ec873bf3137868a9e12e57e8e19cfa5a3a38cec403b741d2f7cd881c51bfd72'  ### INSERT your api secret here ###
    else:
        # Binance
        apikey = ''
        scrkey = ''

    if testnet: fileout = "report/testnet-" + filename
    else: fileout = "report/" + filename

    insIds = ['BTCUSDT', 'ETHUSDT', 'BCHUSDT', 'BNBUSDT']

    # Generate Client object
    client = Client(apikey, scrkey, testnet=testnet)
    client.change_position_mode(dualSide='true')

    # Generate Portfolio object
    portfolio = Portfolio(client, tradeIns=insIds)
    long, short = portfolio.equity_distribution(longPct=0.25,
                                                shortPct=0.25,
                                                currency='USDT',
                                                orderPct=0.05)
    portfolio.position_locks()

    print_('\n' + barstr('', length=100, space_size=0), fileout)
    print_(barstr('BINANCE TRADING', length=100, space_size=5), fileout)
    print_(barstr('', length=100, space_size=0) + '\n', fileout)

    print_('\n' + barstr('Generating Models', length=100, space_size=5) + '\n',
           fileout)
    # Generate Models object
    models = {}
    for i in range(len(portfolio.tradeIns)):
        symbol = portfolio.tradeIns[i]
        client.change_leverage(symbol, 1)
        _data = MarketData(testnet=testnet, symbol=symbol)
        model = TradingModel(symbol=symbol,
                             testnet=testnet,
                             modelType='bollinger',
                             marketData=_data,
                             pdObserve=pd_ob,
                             pdEstimate=pd_es,
                             orderSize=portfolio.orderSize)
        model.build_initial_input()
        only_pos = 'BOTH'
        if symbol in portfolio.locks['BUY']:
            model.add_signal_lock(slock='BUY')
            only_pos = 'SELL ONLY'
        elif symbol in portfolio.locks['SELL']:
            model.add_signal_lock(slock='SELL')
            only_pos = 'BUY ONLY'
        models[symbol] = model
        print_(
            '\tFinish generating model for %s - positions: %s' %
            (symbol, only_pos), fileout)

    print_(
        '\n' + barstr('Start Data Streaming', length=100, space_size=5) + '\n',
        fileout)
    header_print(testnet, client, portfolio, fileout)
    print('\n\tPre-processing Time = %f' % (time.time() - start_time))

    print_('\nStream updating for {} minutes...'.format(pd_ob * min_in_candle),
           fileout)
    signals = wss_run(portfolio, client, testnet, ['@kline_1m'], models,
                      fileout)

    session_summary(signals, fileout)
    print_('\n\tLocal Time at Close: %s ' % timestr(time.time() * 1000),
           fileout)

    print_(
        barstr(text='Elapsed time = {} seconds'.format(
            round(time.time() - start_time, 2))), fileout)
    print_(barstr(text="", space_size=0), fileout)
    os._exit(1)
    apikey = ''
    scrkey = ''
insIds = ['BTCUSDT', 'ETHUSDT', 'BCHUSDT']
stream = ['@depth5@500ms']  ### PROBLEM 1 Modify stream subscription here ###
BidAsk = {}
AggTrades = {}
SymKlns = {}
client = Client(apikey, scrkey, testnet=testnet)
client.change_position_mode(dualSide='true')
for symbol in insIds:
    client.change_leverage(symbol, 1)
    BidAsk[symbol] = []
    AggTrades[symbol] = []
    SymKlns[symbol] = []

print('\n' + barstr(text='Start Data Streaming') + '\n')
header_print(testnet, client)
print('\nStream updating...')
listen_key = client.get_listen_key()
ws = websocket.WebSocketApp(f'{client.wss_way}{listen_key}',
                            on_message=on_message,
                            on_error=on_error,
                            on_close=on_close)
ws.on_open = on_open
ws.run_forever()
client.close_stream()

print('\n\tLocal Time at Close: %s \n' % timestr(time.time() * 1000))
print(
    barstr(text='Elapsed time = {} seconds'.format(
        round(time.time() - start_time, 2))))
def wss_run(*args):
    def on_message(ws, message):
        '''
        Control the message received from 
        '''
        mess = json.loads(message)
        if mess['e'] == 'kline':
            kln = mess['k']
            if kln['x'] is True:
                symbol = kln['s'].upper()
                new_kln = { '_t': int(kln['t']), '_o': float(kln['o']), '_h': float(kln['h']), '_l': float(kln['l']), '_c': float(kln['c']), '_v': float(kln['q']) }
                SymKlns[symbol].append(new_kln)
                print_( '%d. %s\t' % (len(SymKlns[symbol]), symbol) + timestr(new_kln['_t']) + '\t' + \
                        ''.join(['{:>3}:{:<10}'.format(k, v) for k,v in iter(new_kln.items()) if not k=='_t']), fileout)

    def on_error(ws, error):
        '''
        Do something when websocket has an error
        '''
        pass

    def on_close(ws):
        '''
        Do something when websocket closes
        '''
        pass

    def on_open(ws, *args):
        '''
        Main function to run multi-threading
        '''
        def data_stream(*args):
            '''
            First thread to send subscription to the exchange
            '''
            params = [str.lower(ins) + str(s) for ins in insIds for s in stream]
            print_(params, fileout)
            ws.send(json.dumps({"method": "SUBSCRIBE", "params": params, "id": 1 }))
            t1_idx = 0
            while True:
                if len(SymKlns[insIds[0]]) % 5 == 0 and len(SymKlns[insIds[0]]) > t1_idx and len(SymKlns[insIds[0]]) < models[insIds[0]].pdObserve:
                    client.keepalive_stream()
                    t1_idx = len(SymKlns[insIds[0]])

        def strategy(*args):
            '''
            Second thread to generate signals upon the message from the exchange
            '''
            t2_idx = {}
            for symbol in insIds:
                t2_idx[symbol] = 0

            while len(SymKlns[insIds[0]]) < models[insIds[0]].pdObserve:
                for symbol in insIds:
                    sym_ = SymKlns[symbol].copy()
                    if len(sym_) > t2_idx[symbol]:
                        if models[symbol].modelType == 'bollinger':
                            data_ob = pd.DataFrame(sym_)
                            model_sig = models[symbol].get_last_signal(dataObserve=data_ob) 
                        else: model_sig = None
                        if model_sig is not None:
                            ready = True
                            if ready:
                                side, positionSide, startTime = model_sig['side'], model_sig['positionSide'], model_sig['_t']+60*1000
                                expTime, price = startTime + 5*60*1000, round(model_sig['_p'], PRICEPRE[symbol]) #
                                stopLoss = model_sig['atr']
                                takeProfit = model_sig['atr']
                                new_sig = Signal(symbol=symbol, side=side, size=models[symbol].orderSize, orderType='LIMIT', positionSide=positionSide, price=price, startTime=startTime, expTime=expTime, \
                                             stopLoss=stopLoss, takeProfit=takeProfit, timeLimit=models[symbol].pdEstimate*60, timeInForce='GTC')
                                if in_possition_(Signals[symbol], side='BOTH') or position_count(insIds, Signals, side=side) >= portfolio.equityDist[side]:
                                    new_sig.set_expired()
                                else:
                                    for sig in Signals[symbol]:
                                        if sig.is_waiting():
                                            sig.set_expired()
                                            print_('\n\tSet WAITING signal EXPIRED: \n\t' + str(sig), fileout)
                                Signals[symbol].append(new_sig)
                                print_('\n\tFOUND ' + str(new_sig), fileout)
                        t2_idx[symbol] = len(sym_)

        def book_manager(*args):
            '''
            Third thread to excecute/cancel/track the signals generated in strategy()
            '''
            while len(SymKlns[insIds[0]]) < models[insIds[0]].pdObserve:
                time.sleep(1)
                for symbol in insIds:
                    in_position = False
                    last_signal = None
                    for sig in Signals[symbol]:
                        model = models[symbol]
                        sv_time = client.timestamp()
                        if sig.is_waiting():
                            ### Check for EXPIRED order here ###
                            if sv_time > sig.expTime:
                                sig.set_expired()
                                print_('\n\tSet WAITING signal EXPIRED: \n\t' + str(sig), fileout)
                            else:
                                last_signal = sig

                        elif sig.is_ordered():
                            ### Set ACTIVE order here ###
                            in_position = True
                            order_update = client.query_order(symbol, sig.orderId)
                            if order_update['status'] == 'FILLED':
                                sig.set_active(excTime=order_update['updateTime'], excPrice=order_update['avgPrice'], excQty=order_update['executedQty'])                 
                                sig.path_update(lastTime=sig.excTime, lastPrice=sig.excPrice) 
                                print_('\n\tSet BOOKED order ACTIVE: \n\t' + str(sig) + '\n\t' + orderstr(order_update), fileout)


                            ### PROBLEM 3 Insert your code to handle EXPIRED and PARTIALLY_FILLED order here ###


                        elif sig.is_active():
                            ### Control ACTIVE position here ###
                            in_position = True
                            recent_trades = model.marketData.recent_trades(limit=5)
                            for trade in recent_trades:
                                if int(trade['time']) > sig.pricePath[-1]['timestamp']:
                                    sig.path_update({'timestamp': trade['time'], 'price': trade['price']})
                            exit_sign, pos = sig.exit_triggers()
                            if exit_sign:
                                print_('\n\tFound ' + str(exit_sign) + '{}\n'.format(round(pos,4)), fileout)
                                cnt_order = sig.counter_order()
                                order = client.new_order(symbol=symbol, side=cnt_order['side'], orderType='MARKET', quantity=cnt_order['amt'], positionSide=sig.positionSide) #, timeInForce=cnt_order['TIF'], price=lim)
                                sig.set_cnt_ordered(cntorderId=order['orderId'], cntType='MARKET', cntTime=order['updateTime'])
                                print_('\tPlaced COUNTER order: \n\t' + str(sig) + '\n\t' + orderstr(order), fileout)

                        elif sig.is_cnt_ordered():
                            ### Set CLOSED position here ###
                            in_position = True
                            order_update = client.query_order(symbol, sig.cntorderId)
                            if order_update['status'] == 'FILLED':
                                sig.set_closed(clsTime=order_update['updateTime'], clsPrice=order_update['avgPrice'])
                                print_('\n\tClosed order: \n\t' + str(sig) + '\n\t' + orderstr(order_update), fileout)

                    if (not in_position) and (last_signal is not None):
                        ### Check for ENTRY and place NEW order here ###
                        sig = last_signal
                        if sig.orderType == 'MARKET':
                            order  = client.new_order(symbol=symbol, side=sig.side, orderType=sig.orderType, quantity=sig.get_quantity(), positionSide=sig.positionSide)
                            sig.set_ordered(orderId=order['orderId'], orderTime=order['updateTime'], limitPrice=None)
                            print_('\n\tPlaced NEW order: \n\t' + str(sig) + '\n\t' + orderstr(order), fileout)
                        elif sig.orderType=='LIMIT':
                            bids, asks, lim = get_possible_price(model.marketData, sig.side)
                            order = client.new_order(symbol=symbol, side=sig.side, orderType=sig.orderType, quantity=sig.get_quantity(), positionSide=sig.positionSide, timeInForce='GTC', price=lim)
                            sig.set_ordered(orderId=order['orderId'], orderTime=order['updateTime'], limitPrice=lim)
                            print_('\n\tPlaced NEW order: \n\t' + str(sig) + '\n\t' + orderstr(order), fileout)
            ws.close()
        t1 = threading.Thread(target=data_stream)
        t2 = threading.Thread(target=strategy)
        t3 = threading.Thread(target=book_manager) 
        t1.start()
        t2.start()
        t3.start()

    def position_count(insIds, signal_list, side='BOTH'):
        '''
        Returns number of open positions
        '''
        count = 0
        for s in insIds:
            for sig in signal_list[s]:
                if sig.side==side or side=='BOTH':
                    if sig.is_ordered() or sig.is_active() or sig.is_cnt_ordered():
                        count += 1
        return count

    def in_possition_(signal_list, side='BOTH'):
        '''
        Check if there is any open positions
        '''
        in_pos = False
        for sig in signal_list:
            if sig.side==side or side=='BOTH':
                if sig.is_ordered() or sig.is_active() or sig.is_cnt_ordered():
                    in_pos = True
                    break
        return in_pos

    def get_possible_price(mk_data, side):
        '''
        Return a safe limit price available on the market
        '''
        mk_depth = mk_data.order_book(limit=5)
        bids = list(float(x[0]) for x in mk_depth['bids'])
        asks = list(float(x[0]) for x in mk_depth['asks'])
        lim = (side=='BUY')*(bids[0]+bids[1])/2 + (side=='SELL')*(asks[0]+asks[1])/2
        lim = round(lim, PRICEPRE[mk_data.symbol.upper()])
        return bids, asks, lim

    start_time = time.time()
    portfolio, client, testnet, stream, models, fileout = args
    insIds = portfolio.tradeIns
    SymKlns = {}
    Signals = {}
    for symbol in insIds:
       SymKlns[symbol] = []
       Signals[symbol] = []
    
    listen_key = client.get_listen_key()
    ws = websocket.WebSocketApp(f'{client.wss_way}{listen_key}',
                                on_message=on_message, 
                                on_error=on_error,
                                on_close=on_close)
    ws.on_open = on_open
    ws.run_forever()
    client.close_stream()
    
    print_('\n' + barstr('Close Opening Positions', length=100, space_size=5) + '\n', fileout)


    ### PROBLEM 2 Insert your code to close all positions here ###


    return Signals