-
Notifications
You must be signed in to change notification settings - Fork 97
Home
- Deriv API
- Usage examples
- Draft for ContractOptions
- UML diagram of classes
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).
const connection = new WebSocket('wss://frontend.binaryws.com/websockets/v3?l=EN&app_id=1234');
const api = new DerivAPI({ connection });
const api = new DerivAPI({ endpoint: 'frontend.binaryws.com', lang: 'EN', app_id: 1234 });
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();
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);
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).
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 */);
// 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);
})
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);
}
});
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);
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)
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
}
const website_status = await api.websiteStatus();
website_status.onUpdate(({ status, is_website_up, limits }) => {
console.log(`Website is ${status}`);
console.log('limits: %s', limits);
})
const api = new DerivAPI(/* options here */);
const accout = await api.account('YourToken');
const assets = await api.assets();
assets.open_markets.forEach(market => {
console.log('Market %s is open', market.name.full);
});
const underlying = await api.underlying('R_100');
const { callput } = underlying.contract_groups;
const { min: duration, unit: duration_unit } = callput.duration.tick;
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}>
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);
});
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);
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,
});
}
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.
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;
// 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>
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