import * as _ from 'lodash' ; import ibkr , { EventName } from '@stoqey/ib' ; import { IB_HOST , IB_PORT } from '../config' ; import { publishDataToTopic } from '../events/IbkrEvents.publisher' ; import { IBKREVENTS , IbkrEvents } from '../events' ; import { ConnectionStatus } from './connection.interfaces' ; import AccountSummary from '../account/AccountSummary' ; import { Portfolios } from '../portfolios' ; import Orders from '../orders/Orders' ; import includes from 'lodash/includes' ; import { log } from '../log' ; const appEvents = IbkrEvents . Instance ; const clientId = _ . random ( 100 , 100000 ) ; singleton export class IBKRConnection { public status : ConnectionStatus = null ; public IB_PORT : number = IB_PORT ; public IB_HOST : string = IB_HOST ; private static _instance : IBKRConnection ; public ib : ibkr ; public static get Instance ( ) : IBKRConnection { return this . _instance || ( this . _instance = new this ( ) ) ; } private constructor ( ) { } /**
     * init
     */ public init = ( host , port ) : void => { if ( ! this . ib ) { this . ib = new ibkr ( { host , port , } ) ; this . listen ( ) ; } } ; /**
     * initialiseDep
     * Call/Initialize Account summary -> Portfolios -> OpenOrders
     */ public initialiseDep = async ( ) : Promise < boolean > => { try { log ( '1. Account summary' ) ; const accountSummary = AccountSummary . Instance ; accountSummary . init ( ) ; await accountSummary . getAccountSummary ( ) ; log ( '2. Portfolios' ) ; const portfolio = Portfolios . Instance ; await portfolio . init ( ) ; await portfolio . getPortfolios ( ) ; log ( '3. Orders' ) ; const openOrders = Orders . Instance ; await openOrders . init ( ) ; await openOrders . getOpenOrders ( ) ; return true ; } catch ( error ) { log ( 'error initialising IBKR' , error ) ; return false ; } } ; /**
     * On listen for IB connection
     */ private listen = ( ) : void => { const self = this ; function disconnectApp ( ) { publishDataToTopic ( { topic : IBKREVENTS . DISCONNECTED , data : { } , } ) ; self . status = IBKREVENTS . DISCONNECTED ; return log ( IBKREVENTS . DISCONNECTED , `Error connecting client => ${ clientId }` ) ; } this . ib . on ( EventName . connected , function ( ) { async function connectApp ( ) { log ( `.................................................................` ) ; log ( `...... Connected client ${ clientId }, initialising services ......` ) ; const connected = await self . initialiseDep ( ) ; if ( connected ) { publishDataToTopic ( { topic : IBKREVENTS . CONNECTED , data : { connected : true , } , } ) ; self . status = IBKREVENTS . CONNECTED ; log ( `...... Successfully running ${ clientId }'s services ..` ) ; return log ( `.....................................................` ) ; } disconnectApp ( ) ; } connectApp ( ) ; } ) ; this . ib . on ( EventName . error , function ( err ) { const message = err && err . message ; log ( IBKREVENTS . ERROR , `message=${ err && err . message } code=${ err && err . code }` ) ; if ( includes ( message , 'ECONNREFUSED' ) || ( err && err . code === 'ECONNREFUSED' ) ) { return disconnectApp ( ) ; } } ) ; this . ib . on ( EventName . disconnected , function ( ) { log ( IBKREVENTS . DISCONNECTED , `${ clientId } Connection disconnected error` ) ; disconnectApp ( ) ; process . exit ( 1 ) ; } ) ; this . ib . connect ( clientId ) ; appEvents . on ( IBKREVENTS . PING , ( ) => { if ( self . status ) { publishDataToTopic ( { topic : self . status , data : { } , } ) ; } } ) ; } ; /**
     * getIBKR instance
     */ public getIBKR = ( ) : ibkr => { return this . ib ; } ; /**
     * disconnectIBKR
     */ public disconnectIBKR ( ) { this . status = IBKREVENTS . DISCONNECTED ; try { log ( `IBKR Force shutdown ${ clientId } 😴😴😴` ) ; this . ib . disconnect ( ) ; } catch ( error ) { log ( IBKREVENTS . ERROR , error ) ; } } } export default IBKRConnection ;