Skip to content
This repository has been archived by the owner on May 29, 2021. It is now read-only.

Commit

Permalink
Refactor orders history design to remove circular dependencies (#73)
Browse files Browse the repository at this point in the history
  • Loading branch information
ahmedsakr authored Jan 14, 2021
1 parent 46de093 commit 3954949
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 111 deletions.
3 changes: 3 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,8 @@
"sourceType": "module"
},
"rules": {
"no-plusplus": ["error", {
"allowForLoopAfterthoughts": true
}]
}
}
2 changes: 1 addition & 1 deletion dist/wstrade.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "wstrade-api",
"version": "1.1.1",
"version": "1.1.2",
"description": "WealthSimple Trade API Wrapper",
"main": "dist/wstrade.js",
"scripts": {
Expand Down
81 changes: 0 additions & 81 deletions src/api/endpoints.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import Ticker from '../core/ticker';
import myOrders from '../orders';

// The maximum number of orders retrieved by the /orders API.
export const ORDERS_PER_PAGE = 20;

Expand Down Expand Up @@ -248,84 +245,6 @@ const WealthSimpleTradeEndpoints = {
onFailure: defaultEndpointBehaviour.onFailure,
},

/*
* Pull all orders (filled, cancelled, pending) for the specified account under
* the WealthSimple Trade account.
*/
ALL_ORDERS: {
method: 'GET',
url: 'https://trade-service.wealthsimple.com/orders?account_id={0}',
parameters: {
0: 'accountId',
},
onSuccess: async (request) => {
const data = await request.response.json();
const pages = Math.ceil(data.total / ORDERS_PER_PAGE);
const orders = data.results;

if (pages > 1) {
// Query the rest of the pages
for (let page = 2; page <= pages; page++) {
const tmp = await myOrders.page(request.arguments.accountId, page);
orders.push(...tmp.orders);
}
}

return {
total: orders.length,
orders,
};
},
onFailure: defaultEndpointBehaviour.onFailure,
},

/*
* Filters orders by status and ticker.
*/
FILTERED_ORDERS: {
method: 'GET',
url: 'https://trade-service.wealthsimple.com/orders?account_id={0}',
parameters: {
0: 'accountId',
},
onSuccess: async (request) => {
const data = await request.response.json();
const pages = Math.ceil(data.total / ORDERS_PER_PAGE);

const pendingFilter = (order) => {
const { ticker } = request.arguments;
if (ticker) {
const target = new Ticker({ symbol: order.symbol, id: order.security_id });
// order objects don't include exchanges, so we are unable to make
// a strong comparison without requiring a linear increase of
// endpoint calls (which is not reasonable).
//
// The user should provide the security id for a strong comparison here.
if (!ticker.weakEquals(target)) {
return false;
}
}

return order.status === request.arguments.status;
};

const orders = data.results.filter(pendingFilter);
if (pages > 1) {
// Check all other pages for pending orders
for (let page = 2; page <= pages; page++) {
const tmp = await myOrders.page(request.arguments.accountId, page);
orders.push(...tmp.orders.filter(pendingFilter));
}
}

return {
total: orders.length,
orders,
};
},
onFailure: defaultEndpointBehaviour.onFailure,
},

/*
* Cancels a specific order by its id.
*/
Expand Down
100 changes: 73 additions & 27 deletions src/orders/history.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,84 @@ import endpoints, { ORDERS_PER_PAGE } from '../api/endpoints';
import { handleRequest } from '../network/https';
import Ticker from '../core/ticker';

/**
* Collects orders (filled, pending, cancelled) for the provided page and
* account id.
*
* @param {*} accountId The specific account in the WealthSimple Trade account
* @param {*} pageNum The orders page index to seek to
*/
async function page(accountId, pageNum) {
return handleRequest(endpoints.ORDERS_BY_PAGE, {
offset: (pageNum - 1) * ORDERS_PER_PAGE,
accountId,
});
}

/**
* Collects all orders (filled, pending, cancelled) for the specific account.
*
* @param {*} accountId The specific account in the WealthSimple Trade account
*/
async function all(accountId) {
// We start by capturing the first page of orders in order to
// determine the number of pages available
const data = await page(accountId, 1);
const pages = Math.ceil(data.total / ORDERS_PER_PAGE);

if (pages > 1) {
const tasks = [];

// Build the task queue that will retrieve the remaining pages of orders
for (let pageNum = 2; pageNum <= pages; pageNum++) {
tasks.push(page(accountId, pageNum).then((result) => result.orders));
}

// Out-of-order invocation is desired. What matters is that Promise.all will
// guarantee that the data order is preserved.
const result = await Promise.all(tasks);
result.forEach((list) => data.orders.push(...list));

// Update the total attribute to reflect the new size
data.total = data.orders.length;
}

return data;
}

/*
* Retrieves orders that have the specified status.
* Retrieve filtered orders by ticker and status.
*/
const filteredOrders = async (accountId, ticker, status) => handleRequest(endpoints.FILTERED_ORDERS, {
accountId,
ticker: ticker ? new Ticker(ticker) : undefined,
status,
});
async function filteredOrders(accountId, ticker, status) {
// Fetch all orders
const result = await all(accountId);

export default {
const orderFilter = (order) => {
if (ticker) {
const target = new Ticker({ symbol: order.symbol, id: order.security_id });
// order objects don't include exchanges, so we are unable to make
// a strong comparison without requiring a linear increase of
// endpoint calls (which is not reasonable).
//
// The user should provide the security id for a strong comparison here.
if (!new Ticker(ticker).weakEquals(target)) {
return false;
}
}

/**
* Collects orders (filled, pending, cancelled) for the provided page and
* account id.
*
* @param {*} accountId The specific account in the WealthSimple Trade account
* @param {*} page The orders page index to seek to
*/
page: async (accountId, page) => handleRequest(endpoints.ORDERS_BY_PAGE, {
offset: (page - 1) * ORDERS_PER_PAGE,
accountId,
}),
return order.status === status;
};

/**
* Collects all orders (filled, pending, cancelled) for the specific account.
*
* @param {*} accountId The specific account in the WealthSimple Trade account
*/
all: async (accountId) => handleRequest(endpoints.ALL_ORDERS, {
offset: 0,
accountId,
}),
// Apply filter to the result
result.orders = result.orders.filter(orderFilter);
result.total = result.orders.length;
return result;
}

export default {

page,
all,

/**
* Retrieves pending orders for the specified security in the account.
Expand Down

0 comments on commit 3954949

Please sign in to comment.