import 'isomorphic-fetch' ; import { CandleResolution , Candles , Currencies , MarketInstrument , MarketInstrumentList , MarketOrderRequest , Operations , Order , Orderbook , PlacedLimitOrder , PlacedMarketOrder , Portfolio , PortfolioPosition , SandboxSetCurrencyBalanceRequest , SandboxSetPositionBalanceRequest , LimitOrderRequest , UserAccounts , } from './domain' ; import { CandleStreaming , Depth , HttpMethod , InstrumentId , Interval , OrderbookStreaming , FIGI , InstrumentInfoStreaming , InstrumentInfoStreamingMetaParams , CandleStreamingMetaParams , StreamingError , } from './types' ; import { URLSearchParams } from 'url' ; import Streaming from './Streaming' ; export * from './types' ; export * from './domain' ; const omitUndef = ( x ) => JSON . parse ( JSON . stringify ( x ) ) ; function getQueryString ( params ) { const searchParams = new URLSearchParams ( omitUndef ( params ) as any ) . toString ( ) ; return searchParams . length ? `?${ searchParams }` : '' ; } type OpenApiConfig = { apiURL : string ; socketURL : string ; secretToken : string ; brokerAccountId ? : string ; } ; type RequestConfig < Q , B > = { method ? : HttpMethod ; query ? : Q ; body ? : B ; } ; export default class OpenAPI { private _streaming : Streaming ; private _sandboxCreated : boolean = false ; private _currentBrokerAccountId : string | undefined = undefined ; private readonly apiURL : string ; private readonly secretToken : string ; private readonly authHeaders : any ; param apiURL param socketURL param secretToken param brokerAccountId constructor ( { apiURL , socketURL , secretToken , brokerAccountId } ) { this . _streaming = new Streaming ( { url : socketURL , secretToken } ) ; this . _currentBrokerAccountId = brokerAccountId ; this . apiURL = apiURL ; this . secretToken = secretToken ; this . authHeaders = { Authorization : 'Bearer ' + this . secretToken , 'Content-Type' : 'application/json' , } ; } /**
     * Запрос к REST
     */ private async makeRequest < Q , B , R > ( url , { method = 'get' , query , body } = { } ) { let requestParams = { method , headers : this . authHeaders } ; let requestUrl = this . apiURL + url + getQueryString ( query || { } ) ; if ( method === 'post' ) { requestParams . body = JSON . stringify ( body ) ; } const res = await fetch ( requestUrl , requestParams ) ; if ( res . status === 401 ) { throw { status : 'Error' , message : 'Unauthorized! Try to use valid token. https://tinkoffcreditsystems.github.io/invest-openapi/auth/' , } ; } if ( res . status === 429 ) { throw { status : 'Error' , message : 'Too Many Requests!' , } ; } if ( ! res . ok ) { throw await res . json ( ) ; } const data = await res . json ( ) ; return data . payload ; } /**
     * Регистрация песочницы
     */ private sandboxRegister ( ) { if ( ! this . _sandboxCreated ) { this . makeRequest ( '/sandbox/register' , { method : 'post' } ) ; this . _sandboxCreated = true ; } } /**
     * Метод возвращает текущий номер счета (*undefined* - значение по умолчанию для счета Тинькофф).
     */ getCurrentAccountId ( ) { return this . _currentBrokerAccountId ; } param brokerAccountId setCurrentAccountId ( brokerAccountId ) { this . _currentBrokerAccountId = brokerAccountId ; } /**
     * Метод для очистки песочницы
     */ async sandboxClear ( ) { await this . sandboxRegister ( ) ; return this . makeRequest ( '/sandbox/clear' , { method : 'post' , query : { brokerAccountId : this . _currentBrokerAccountId } , } ) ; } param params async setPositionBalance ( params ) { await this . sandboxRegister ( ) ; return this . makeRequest ( '/sandbox/positions/balance' , { method : 'post' , query : { brokerAccountId : this . _currentBrokerAccountId } , body : params , } ) ; } param params async setCurrenciesBalance ( params ) { await this . sandboxRegister ( ) ; return this . makeRequest ( '/sandbox/currencies/balance' , { method : 'post' , query : { brokerAccountId : this . _currentBrokerAccountId } , body : params , } ) ; } /**
     * Метод для получение портфеля цб
     */ portfolio ( ) { return this . makeRequest ( '/portfolio' , { query : { brokerAccountId : this . _currentBrokerAccountId } , } ) ; } /**
     * Метод для получения валютных активов клиента
     */ portfolioCurrencies ( ) { return this . makeRequest ( '/portfolio/currencies' , { query : { brokerAccountId : this . _currentBrokerAccountId } , } ) ; } param params instrumentPortfolio ( params ) { return this . portfolio ( ) . then ( ( x ) => { return ( x . positions . find ( ( position ) => { if ( 'figi' in params ) { return position . figi === params . figi ; } if ( 'ticker' in params ) { return position . ticker === params . ticker ; } } ) || null ) ; } ) ; } param figi param lots param operation param price limitOrder ( { figi , lots , operation , price , } ) { return this . makeRequest ( '/orders/limit-order' , { method : 'post' , query : { figi , brokerAccountId : this . _currentBrokerAccountId , } , body : { lots , operation , price , } , } ) ; } param figi param lots param operation param price marketOrder ( { figi , lots , operation } ) { return this . makeRequest ( '/orders/market-order' , { method : 'post' , query : { figi , brokerAccountId : this . _currentBrokerAccountId , } , body : { lots , operation , } , } ) ; } param orderId cancelOrder ( { orderId } ) { return this . makeRequest ( `/orders/cancel` , { method : 'post' , query : { orderId , brokerAccountId : this . _currentBrokerAccountId , } , } ) ; } /**
     * Метод для получения всех активных заявок
     */ orders ( ) { return this . makeRequest ( '/orders' , { query : { brokerAccountId : this . _currentBrokerAccountId } , } ) ; } /**
     * Метод для получения всех доступных валютных инструментов
     */ currencies ( ) { return this . makeRequest ( '/market/currencies' ) ; } /**
     * Метод для получения всех доступных валютных ETF
     */ etfs ( ) { return this . makeRequest ( '/market/etfs' ) ; } /**
     * Метод для получения всех доступных облигаций
     */ bonds ( ) { return this . makeRequest ( '/market/bonds' ) ; } /**
     * Метод для получения всех доступных акций
     */ stocks ( ) { return this . makeRequest ( '/market/stocks' ) ; } param from param to param figi operations ( { from , to , figi } ) { return this . makeRequest ( '/operations' , { query : { from , to , figi , brokerAccountId : this . _currentBrokerAccountId , } , } ) ; } param from param to param figi param interval candlesGet ( { from , to , figi , interval = '1min' , } ) { return this . makeRequest ( '/market/candles' , { query : { from , to , figi , interval } , } ) ; } param figi param depth orderbookGet ( { figi , depth = 3 } ) { return this . makeRequest ( '/market/orderbook' , { query : { figi , depth } , } ) ; } param params { figi search ( params ) { if ( 'figi' in params ) { return this . makeRequest < any , never , MarketInstrument > ( '/market/search/by-figi' , { query : { figi : params . figi } , } ) . then ( ( x ) => ( x ? { total : 1 , instruments : [ x ] } : { total : 0 , instruments : [ ] } ) ) ; } if ( 'ticker' in params ) { return this . makeRequest ( '/market/search/by-ticker' , { query : { ticker : params . ticker } , } ) ; } throw new Error ( 'should specify figi or ticker' ) ; } param params { figi searchOne ( params ) { return this . search ( params ) . then ( ( x ) => x . instruments [ 0 ] || null ) ; } example param figi param depth param cb return orderbook ( { figi , depth = 3 } , cb = console . log ) { return this . _streaming . orderbook ( { figi , depth } , cb ) ; } example param figi param interval param cb return candle ( { figi , interval = '1min' } , cb = console . log ) { return this . _streaming . candle ( { figi , interval } , cb ) ; } example param figi param cb return instrumentInfo ( { figi } , cb = console . log ) { return this . _streaming . instrumentInfo ( { figi } , cb ) ; } example param cb return onStreamingError ( cb ) { return this . _streaming . onStreamingError ( cb ) ; } /**
     * Метод для получения брокерских счетов клиента
     */ accounts ( ) { return this . makeRequest ( '/user/accounts' ) ; } }