Giter VIP home page Giter VIP logo

ig-api's Introduction

Minimalistic wrapper around IG's API

Install

yarn add ig-api

Usage

import IG from 'ig-api'

const ig = new IG(apiKey, isDemo)

// Using promises
ig.login(username, password)
  // Response data is automatically
  // passed to the resolve callback
  .then((summary) => {
    console.log('summary:', summary)
    // Once logged in, use the shorthand
    // get(), post(), put() and delete()
    // methods to interact with IG's API
    ig.get('positions')
      .then((positions) => {
        console.log('positions:', positions)
      })
  })
  // Errors are automatically transformed
  // into a more user friendly format with
  // the response status and IG error code
  .catch(console.error)

// Using async await
try {
  await ig.login(username, password)
  const positions = await ig.get('positions')
  console.log('positions:', positions)
} catch (error) {
  console.error(error)
}

Instance API

// ES6 Module
import IG from 'ig-api'

// Common JS
const IG = require('ig-api')

The IG class is a minimalistic wrapper around axiosโ€”a Promise based HTTP client that works in browsers and node. IG class instances take care of setting the request URL, headers and authentication tokens when logging into an account.

Responses and errors are automatically transformed into a more user friendly format, though this can be customised or disabled if desired. See options for more information.

constructor(apiKey, isDemo, options)

parameter type required description
apiKey string true Application API key
isDemo boolean false Is the API key associated with a demo account? Defaults to false
options object false See options for more information

login(username, password, encryptPassword, options)

parameter type required description
username string true Account user name
password string true Account password
encryptPassword boolean false Encrypt password before posting to API. Defaults to false
options object false See options for more information

logout(options)

parameter type required description
options object false See options for more information

request(method, path, version, config, options)

parameter type required description
method string true Request method to use ('get', 'post', 'put' or 'delete')
path string true Endpoint path eg. 'history/transactions'
version number false Endpoint version (1, 2 or 3). Defaults to 1
config object false Request config to pass to axios. See documentation
options object false See options for more information

get(path, version, params, options)

Shorthand to request, passing 'get' as the method and params as the key value to config.

// Get detailed account activity since 25th December 2016
ig.get('history/activity', 3, {
  from: '2016-12-25',
  detailed: true
})
// ...is the same as
ig.request('get', 'history/activity', 3, {
  params: {
    from: '2016-12-25',
    detailed: true
  }
})

post(path, version, data, options)

Shorthand to request, passing 'post' as the method and data as the key value to config.

// Create a new watchlist
ig.post('watchlist', 1, {
  name: 'Forex Majors',
  epics: [
    'CS.D.AUDUSD.TODAY.IP', // AUD/USD
    'CS.D.EURGBP.TODAY.IP', // EUR/GBP
    'CS.D.EURUSD.TODAY.IP', // EUR/USD
  ]
})
// ...is the same as
ig.request('post', 'watchlist', 1, {
  data: {
    name: 'Forex Majors',
    epics: [
      'CS.D.AUDUSD.TODAY.IP', // AUD/USD
      'CS.D.EURGBP.TODAY.IP', // EUR/GBP
      'CS.D.EURUSD.TODAY.IP', // EUR/USD
    ]
  }
})

put(path, version, data, options)

Shorthand to request, passing 'put' as the method and data as the key value to config.

// Switch active account
ig.put('session', 1, {
  accountId: 'XXXXX'
})
// ...is the same as
ig.request('put', 'session', 1, {
  data: {
    accountId: 'XXXXX'
  }
})

delete(path, version, data, options)

Shorthand to request, passing 'delete' as the method and data as the key value to config.

// Close a position
ig.delete('positions/otc', 1, {
  epic: 'UA.D.AAPL.DAILY.IP', // AAPL DFB
  orderType: 'MARKET',
  direction: 'SELL',
  expiry: 'DFB',
  size: 0.5
})
// ...is the same as
ig.request('delete', 'positions/otc', 1, {
  data: {
    epic: 'UA.D.AAPL.DAILY.IP', // AAPL DFB
    orderType: 'MARKET',
    direction: 'SELL',
    expiry: 'DFB',
    size: 0.5
  }
})

Static API

IG.transformResponse(response)

parameter type required description
response object true Response object

Simply returns response.data.

IG.transformError(error)

parameter type required description
error object true Error object

Throws a new Error from error with additional key values. See errors for more detail.

IG.uniqueId(length, chars)

parameter type required description
length number false Length of the unique id. Defaults to 15
chars string false Chars to use. Defaults to [A-Z0-9]

Creates a unique id that matches IG's format of 15 uppercase alphanumeric characters eg. ABCDE12345WVXYZ.

This can be useful when opening a new position and providing a unique dealReference.

Options

The IG constructor and all instance methods take an options argument as the final parameter.

The options object has the following shape:

{
  transformResponse: false || function(response) {
    // Transform and return a custom response
    return response
  },
  transformError: false || function(error) {
    // Transform and throw a custom error
    throw error
  }
}

Both transformResponse and transformError can be specified as functions or disabled by passing false.

By default, the built-in transform functions are used. See IG.transformResponse and IG.transformError.

When setting transformResponse to false, the original response object is returned from the request's resolve method. This is useful if you want to access the response headers or status code for example.

When setting transformError to false, the original error object is thrown from the request's reject method. This is useful if you want to access the error request or response objects and throw your own custom error.

You can also specify your own custom transform functions that map the response and error objects to whatever you so choose.

For example if you wanted to return the response data and status code for all requests on an instance and customise the error:

import IG from 'ig-api'

const ig = new IG(apiKey, isDemo, {
  transformResponse(response) {
    return {
      code: response.status,
      data: response.data
    }
  },
  transformError(error) {
    throw new Error(`Uh oh! ${error.message}`)
  }
})

const customResponse = await ig.login(username, password)
console.log(customResponse) // { code: 200, data: { ... } }

If you want to use the built-in transform functions in your own code, they are available as static properties on the IG class:

import IG from 'ig-api'

const ig = new IG(apiKey, isDemo, {
  transformResponse(response) {
    // Do something with the response...
    return IG.transformResponse(response)
  },
  transformError(error) {
    // Do something with the error...
    IG.transformError(error) // throw is called within IG.transformError
  }
})

Passing an options object to the IG constructor (as shown above) serves as a way for setting the default transform functions for all requests on that instance.

If you want to override these transformation functions on a call-by-call basis, you can do so by passing an options object when calling an instance method:

import IG from 'ig-api'

const ig = new IG(apiKey, isDemo)

// Default configuration
const summary = await ig.login(username, password)
console.log(summary) // response.data object by default

// Disable response transform on single call
const response = await ig.login(username, password, {
  transformResponse: false
})
console.log(response) // original response object

// Customise response transform on single call
const status = await ig.login(username, password, {
  transformResponse: (response) => response.status
})
console.log(status) // 200

Errors

Unless the transformError function is disabled or overridden via options, all request errors are handled by the built-in transform function.

When an error is thrown from a request, a new Error is created that has the following shape:

key description
type Either 'request', 'response' or 'internal'
message Error message
url Request url
data Request data
params Request params
method Request method
headers Request headers
statusCode Response status code (type: 'response' only)
statusText Response status text (type: 'response' only)
errorCode Response IG error code (type: 'response' only)

Using type and errorCode can be very useful for handling IG error codes within your application:

ig.login(username, password)
  .catch((error) => {
    if (error.type === 'response') {
      switch (error.errorCode) {
        case 'error.security.invalid-details':
          alert('Incorrect username or password')
          break;
        default:
          console.error(error.errorCode)
          break;
      }
    } else {
      console.error(error.message)
    }
  })

Promises

This library depends on a native ES6 Promise implementation to be supported.

If your environment doesn't support ES6 Promises, you can polyfill.

Testing

To run the tests locally, you will need to create a .env file at the root of the repository that contains the following:

DEMO_API_KEY=yourDemoApiKey
DEMO_USERNAME=yourDemoUsername
DEMO_PASSWORD=yourDemoPassword

Creating API Keys

Since tests mutate your account by creating and deleting watchlists, you must use a demo account and API key.

I will not take any resposibility for running tests using your live account credentials!

To create an API key, login to IG and go to:

My IG > Settings > API keys

Here you will be able to create API keys for both your live and demo accounts.

If you don't have a demo account, you will need to create one.

NOTE: After creating a demo account for the first time, it is important that you login to your account, go to the Dashboard and make one of your demo accounts a default by clicking the radio button next to it. If you don't do this, you will get a "Transformation failure" error when attempting to login using your demo credentials.

Running Tests

Tests are written using jest. To run the tests:

yarn test

To run the tests continuously during development:

yarn test:watch

Author

Matthew Wagerfield

License

MIT

ig-api's People

Contributors

wagerfield avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

ig-api's Issues

Dependency upgrade request: `[email protected]`

Hi @wagerfield,

A bug was fixed in [email protected], see: nikvdp/pidcrypt#5. (This was also discussed in #2.)

ig-api is currently has its pidcrypt dependency set to ^0.0.31: https://github.com/wagerfield/ig-api/blob/master/package.json#L36.

This prevents npm from using [email protected], and taking advatage of this bug fix, as the use of a caret range prevents changes to the 'left-most non-zero element in the [major, minor, patch] tuple' i.e. 31 (see https://github.com/npm/node-semver#caret-ranges-123-025-004).

I wonder if it would be possible to update pidcrypt to 0.0.32 in the package.json, and publish a new version to npm?

I did attempt to create a PR on a branch with this change, but did not have permission to do so, however all tests passed after I had made the change locally.

Thanks!

Npm audit detects vulnerabilities

Hi everyone! And firstly thanks for this repo. I recently detected this.

When passing npm audit into a project using version 0.15.0

                   === npm audit security report ===

Moderate Denial of Service
Package axios
Patched in >=0.18.1
Dependency of ig-api
Path ig-api > axios
More info https://npmjs.com/advisories/880

Since there is a moderate risk, Is it posible to update it to use axios latest version? or at least 0.18.1 as requested?
Can i do it?

Doesn't work in Node.js

Due to the use of pidcrypt, I currently get the error below when running in a Node.js environment:

if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
________________^
ReferenceError: navigator is not defined

Also, it doesnt look like something that will be fixed: nikvdp/pidcrypt#5

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.