Skip to content
Amin Marashi edited this page Aug 2, 2019 · 40 revisions

Table of contents

Deriv API

API instantiation

You can either create an instance of WebSocket and pass it as connection or pass the endpoint and app_id to the constructor to create the connection for you.

If you pass the connection it's up to you to reconnect in case the connection drops (cause API doesn't know how to create the same connection).

Examples

Passing a connection

const connection = new WebSocket('wss://frontend.binaryws.com/websockets/v3?l=EN&app_id=1234');
const api = new DerivAPI({ connection });

With endpoint and app_id

const api = new DerivAPI({ endpoint: 'frontend.binaryws.com', lang: 'EN', app_id: 1234 });

Asynchronous Requests

High-level API

This level of API provides abstract objects that are populated using the data received from one or more calls to the WebSocket API. The advantage of using these objects is that they're not expected to change after the underlying API calls are changed.

They're also designed to be usable by the Front-end applications and hide many complexities of dealing with data and call handling.

There are two types of abstract objects you can request from the API, Immutable and Stream, the main difference is that Streams provide onUpdate to subscribe to changes:

// Request the balance stream from the API
const balance = await account.balance();

el_balance_view.setBalance(`${balance.currency} ${balance.format}`);

// onUpdate accepts an optional callback and returns an RxJS Observable
balance.onUpdate(updateBalanceView).subscribe(console.log);

// Updates are reflected to the balance object automatically
console.log(`New balance: ${balance.currency} ${balance.format}`);

Stream objects subscribe to the related calls and keep their data up-to-date at any given time, making it easier to use with MobX observables or any other library that can listen on variable changes.

onUpdate accepts an optional callback, which if passed will be called with the updated abstract object (not the API response). It also always returns an RxJS Observable which is a stream of updates to the abstract object (again, note that this is not the response from the API).

Immutable objects don't have onUpdate and they're not expected to change during a normal session of the API usage:

// Account is an Immutable object, therefore won't change
const account = await api.acccount(token);

const { loginid, email } = account;

// Account also provides a balance stream
const balance_stream = await account.balance();

Low-level API

You'd create a low-level API instance with the same arguments as the high-level API:

const api = new DerivAPIBasic({ endpoint: 'frontend.binaryws.com', lang: 'EN', app_id: 1234 });

To interact with the API through the API calls, this is tightly coupled with the WebSocket API and will change with every change to the API, therefore is not preferred to be used directly in Front-end applications.

There are two async operations available, subscription and request. A request is a one-off async request sent and the result is a Promise that resolves to the response of that request:

// balance is the API response for current balance
const { balance } = await api.balance();

On the other hand, a subscription is handled through two different calls: subscribe and subscribeWithCallback. The subscribe call returns an RxJS Observable which returns subscriptions responses or errors, as defined by the RxJS API. As suggested by the name, subscribeWithCallback calls the callback passed to it with the responses received from the API:

// With RxJS: store the last two balance responses in an Array
const last_two_balances = api.subscribe({ balance: 1 }).pipe(take(2), toArray()).toPromise();

// Callback: print the balance responses
api.subscribeWithCallback({ balance: 1 }, console.log);

API Methods

All API methods are asynchronous, they return a Promise that will resolve to an abstract object with the requested data and onUpdate() which receives the updated instance on every update of that object either through a callback passed to onUpdate() or as an observer listening on the observable returned by onUpdate() (if no callback is specified).

ticks

const range = { start: await api.time - 10, end: await api.time };

// a ticks object you can get the ticks from or listen to updates
const ticks = await api.ticks('R_100');

// By default the last 1000 ticks
const list_of_ticks = ticks.list;
const list_of_old_ticks = await ticks.history(range);

// Get the tick updates with a callback
ticks.onUpdate(tick => /* updates for the ticks */);


// Get the tick updates with an observable
ticks.onUpdate().subscribe(tick => /* updates for the ticks */);

candles

// Same as ticks, default is the last 1000 1min candle
// either 'R_100' or { symbol: 'R_100', granularity: ... }
const candles = await api.candles('R_100');

const candle = candles.list.slice(-1)[0] // current

candles.onUpdate(candle => {
    chart.add(candle);
})

contract

const contract = await api.contract({
    contract_type: 'call',
    symbol: 'R_100',
    duration: 1,
    duration_unit: 't',
    ...contract_options
});

contract.onUpdate().subscribe(contract => {
    if (contract.is_sold) {
        sell_pop_up.set(contract);
    }
});

underlying

const underlying = await api.underlying('R_100');

// You can also call ticks and candles related calls on an underlying instance
const ticks = await underlying.ticks();

// You can create a contract from an underlying
const contract = await underlying.contract(contract_options);

account

const account = await api.account('AccountToken');
const balance = account.balance;

// You can create a contract from an account instance
const contract = await account.contract(contract_options);

const transactions = await account.transactions();

transactions.onUpdate(console.log)

assets

const assets = await api.assets();
if (!assets.underlyings.find(u => u.symbol === 'R_100').is_trading_suspended) {
    const contract = await api.contract(contract_options);
    // The rest
}

websiteStatus

const website_status = await api.websiteStatus();

website_status.onUpdate(({ status, is_website_up, limits }) => {
    console.log(`Website is ${status}`);

    console.log('limits: %s', limits);
})

Usage examples

Short examples

const api = new DerivAPI(/* options here */);

Authenticate to an account using token

const accout = await api.account('YourToken');

Get all the assets info

const assets = await api.assets();

assets.open_markets.forEach(market => {
    console.log('Market %s is open', market.name.full);
});

Ask for an specific underlying

const underlying = await api.underlying('R_100');

Get a contract group by its name

const { callput } = underlying.contract_groups;

Get supported durations for a contract group

const { min: duration, unit: duration_unit } = callput.duration.tick;

Create a datepicker for forward starting sessions

const { forward_sessions } = callput;

const [ first_session ] = forwardSessions;

const $el = <input type="date" value={await api.time} min={first_session.open.value} max={first_session.close.value}>

Examples with more details

An account object

const account = await api.account('YourToken');

// Loop through all associated accounts and print whether they're virtual
account.siblings.forEach(u => {
    console.log('Is %s virtual? %s', u.loginid, u.is_virtual);
});

const sibling = await account.siblings[0].switch();

// account.balance is not available anymore.

const balance = sibling.balance;

console.log('%s has %s %s', sibling.loginid, balance.currency, balance.format);

balance.onUpdate(({ account: { loginid }, currency, format }) => {
    console.log('%s has now %s %s', loginid, currency, format);
});

Create an underlying and get all the ticks history for showing on a chart

const underlying = await api.underlying('R_100');

const ticks = await underlying.ticks();

ticks.onUpdate(tick => {
    // Update chart info with the new ticks
    chart.show(tick);
});

// Initialize the chart with the list of ticks available
chart.init(ticks.list);

Create a contract if trading is allowed for an underlying

const underlying = await api.underlying('R_100');

if (underlying.is_trading_suspended) {
    console.log('Trading is suspended for %s', underlying.name.full);
} else {
    // Get the contract group for Rise/Fall
    const callput = underlying.contract_groups.callput;

    // Get the duration allowed for tick contracts
    const { value: duration, unit: duration_unit } = callput.durations.tick.min;

    const [contract_type] = callput.contract_types;

    const contract = await api.contract({
        symbol: underlying.symbol,
        contract_type,
        duration,
        duration_unit,
    });
}

Draft for ContractOptions

The contract options is a nested object containing info about different aspects of a contract creation. The values in this options can be used to populate various inputs in the trading page of FE apps.

Contract options structure

const { contract_options } = R_100;

const {
  categories: {
      higher_lower: {
          name: FullName,
          contract_types: ['CALL', 'PUT'],
          bases: ['stake', 'payout'],
          forward_starting: {
              1564531200 : {
                  min: CustomDate,
                  max: CustomDate,
              }
          },
          expiry_types: {
              end_time: {
                  min: CustomDate,
                  max: CustomDate,
                  barriers: {
                      high: Barrier,
                      low: Barrier,
                      single: Barrier,
                  },
              },
              duration: {
                  m: {
                      min: CustomDate,
                      max: CustomDate,
                      barriers: {
                          high: Barrier,
                          low: Barrier,
                          single: Barrier,
                      },
                  }
              }
          },
      }
  },
  currencies,
} = contract_options;

React render example

// in the render function

const { contract_options } = this.props;
const {
    proposals,
    start_time,
    expiry_type,
    expiry_time,
    duration,
    duration_unit,
    basis,
    currency,
    amount,
    barriers,
} = this.state;

<form>
  Object.values(contract_options.categories).map(option => {
    return (<label>{option.name.full}</label>
           <input
             type="radio"
             name="contract_category"
             checked={category === option}
             onChange={() => this.updateCategory(option)}
           />)
  });

  if (objectNotEmpty(category.forward_starting)) {
    <dropdown>
      {t('Start date:')}
      Object.values(category.forward_starting).map(option => {
        return <option
                 selected={ option === start_session }
                 onChange={() => this.updateStartSession(option)}
               >
                 {showDate(option.min)}
               </option>
      });
    </dropdown>
  } else {
    <div />
  }

  if (start_session) {
    {t('Start time:')}
    <Datepicker
      min={start_session.min}
      max={start_session.max}
      value={start_time}
      onUpdate(this.updateStartTime)
    />
  } else {
    <div />
  }

  Object.values(category.expiry_types).map(option => {
    return (
           <label>{expiry_type === category.expiry_types.duration ? t('Duration') : t('End time')}</label>
           <input
             type="radio"
             name="expiry_type"
             checked={ expiry_type === option }
             onChange={() => this.updateExpiryType(option)}
           />)
  });

  if (expiry_type.code === 'end_time') {
    {t('End Time:')}
    <Datepicker
      min={expiry_type.min}
      max={expiry_type.max}
      value={expiry_time}
      onUpdate(this.updateExpiryTime)
    />
  } else {
    {t('Duration')}
    <dropdown>
      Object.values(expiry_type.duration_units).map(option => {
        return <option
                 selected={ option.unit === duration_unit.unit }
                 value={ option.unit }
                 onChange={() => this.updateDurationUnit(option)}
               >
                 {displayUnit(option.unit)}
               </option>
      });
    </dropdown>

    <input
      type="range"
      min={ duration_unit.min }
      max={ duration_unit.max }
      value={ duration }
      onUpdate={this.updateDuration}
      class="slider"
    />
  }

  {t('Basis:')}
  Object.values(category.bases).map(option => {
      return (
        <label>{basis === 'stake' ? t('Stake') : t('Payout')}</label>
        <input
          type="radio"
          name="basis"
          value={basis}
          checked={ basis === option }
          onChange={() => this.updateBasis(option)}
        />
      );
  });

  {t('Amount')}
  <dropdown>
  Object.values(contract_options.currencies).map(option => {
          return <option
          selected={ option === currency }
          value={ currency }
          onChange={() => this.updateCurrency(option)}
          >
          {displayCurrency(currency)}
          </option>
          });
</dropdown>
  <input type="number" value={amount} onUpdate={this.updateAmount} />

  Object.values(category.contract_types).map(contract_type => {
    return proposals[contract_type] ? <button
             type="submit"
             onClick={ this.buy(proposals[contract_type]) }
           >
             {displayContractType(contract_type)}
           </button>
           : <div />
  });
</form>

UML diagram of classes

Each font face indicates a different type of field:

Bold: a link to another class object(s)

endingWithParenthesis(): A method name, usually doing some action on the object

normal_properties: The snake case name of a property accessible from the object

Deriv API UML Diagram