Loëck Vézien
7 years ago
committed by
GitHub
7 changed files with 274 additions and 76 deletions
@ -0,0 +1,135 @@ |
|||||
|
import { getBalanceHistoryForAccount, getBalanceHistoryForAccounts } from 'helpers/balance' |
||||
|
|
||||
|
const counterValues = { |
||||
|
'BTC-USD': { |
||||
|
'2018-01-01': 1000, |
||||
|
'2018-01-02': 2000, |
||||
|
'2018-01-03': 3000, |
||||
|
'2018-01-04': 4000, |
||||
|
'2018-01-05': 5000, |
||||
|
}, |
||||
|
} |
||||
|
|
||||
|
describe('helpers > balance', () => { |
||||
|
describe('getBalanceHistoryForAccount', () => { |
||||
|
test('should handle a simple case', () => { |
||||
|
const account = { |
||||
|
coinType: 0, |
||||
|
balanceByDay: { |
||||
|
'2018-01-01': 100000000, |
||||
|
'2018-01-02': 200000000, |
||||
|
}, |
||||
|
} |
||||
|
|
||||
|
const interval = { |
||||
|
start: '2018-01-01', |
||||
|
end: '2018-01-02', |
||||
|
} |
||||
|
|
||||
|
const balances = getBalanceHistoryForAccount({ |
||||
|
fiat: 'USD', |
||||
|
account, |
||||
|
counterValues, |
||||
|
interval, |
||||
|
}) |
||||
|
|
||||
|
expect(balances).toEqual([ |
||||
|
{ date: '2018-01-01', balance: 1000 }, |
||||
|
{ date: '2018-01-02', balance: 4000 }, |
||||
|
]) |
||||
|
}) |
||||
|
|
||||
|
test('should handle empty days', () => { |
||||
|
const account = { |
||||
|
coinType: 0, |
||||
|
balanceByDay: { |
||||
|
'2018-01-01': 100000000, |
||||
|
'2018-01-03': 200000000, |
||||
|
}, |
||||
|
} |
||||
|
|
||||
|
const interval = { |
||||
|
start: '2018-01-01', |
||||
|
end: '2018-01-03', |
||||
|
} |
||||
|
|
||||
|
const balances = getBalanceHistoryForAccount({ |
||||
|
fiat: 'USD', |
||||
|
account, |
||||
|
counterValues, |
||||
|
interval, |
||||
|
}) |
||||
|
|
||||
|
expect(balances).toEqual([ |
||||
|
{ date: '2018-01-01', balance: 1000 }, |
||||
|
{ date: '2018-01-02', balance: 2000 }, |
||||
|
{ date: '2018-01-03', balance: 6000 }, |
||||
|
]) |
||||
|
}) |
||||
|
|
||||
|
test('should work if interval dont contain transactions', () => { |
||||
|
const account = { |
||||
|
coinType: 0, |
||||
|
balanceByDay: { |
||||
|
'2018-01-01': 100000000, |
||||
|
}, |
||||
|
} |
||||
|
|
||||
|
const interval = { |
||||
|
start: '2018-01-02', |
||||
|
end: '2018-01-03', |
||||
|
} |
||||
|
|
||||
|
const balances = getBalanceHistoryForAccount({ |
||||
|
fiat: 'USD', |
||||
|
account, |
||||
|
counterValues, |
||||
|
interval, |
||||
|
}) |
||||
|
|
||||
|
expect(balances).toEqual([ |
||||
|
{ date: '2018-01-02', balance: 2000 }, |
||||
|
{ date: '2018-01-03', balance: 3000 }, |
||||
|
]) |
||||
|
}) |
||||
|
}) |
||||
|
|
||||
|
describe('getBalanceHistoryForAccounts', () => { |
||||
|
test('should merge multiple accounts balance', () => { |
||||
|
const account1 = { |
||||
|
coinType: 0, |
||||
|
balanceByDay: { |
||||
|
'2018-01-01': 100000000, |
||||
|
'2018-01-02': 200000000, |
||||
|
}, |
||||
|
} |
||||
|
|
||||
|
const account2 = { |
||||
|
coinType: 0, |
||||
|
balanceByDay: { |
||||
|
'2018-01-02': 500000000, |
||||
|
'2018-01-04': 600000000, |
||||
|
}, |
||||
|
} |
||||
|
|
||||
|
const interval = { |
||||
|
start: '2018-01-01', |
||||
|
end: '2018-01-04', |
||||
|
} |
||||
|
|
||||
|
const balances = getBalanceHistoryForAccounts({ |
||||
|
fiat: 'USD', |
||||
|
accounts: [account1, account2], |
||||
|
counterValues, |
||||
|
interval, |
||||
|
}) |
||||
|
|
||||
|
expect(balances).toEqual([ |
||||
|
{ date: '2018-01-01', balance: 1000 }, |
||||
|
{ date: '2018-01-02', balance: 14000 }, |
||||
|
{ date: '2018-01-03', balance: 21000 }, |
||||
|
{ date: '2018-01-04', balance: 32000 }, |
||||
|
]) |
||||
|
}) |
||||
|
}) |
||||
|
}) |
@ -0,0 +1,117 @@ |
|||||
|
// @flow
|
||||
|
|
||||
|
import moment from 'moment' |
||||
|
import isUndefined from 'lodash/isUndefined' |
||||
|
import { getDefaultUnitByCoinType } from '@ledgerhq/currencies' |
||||
|
|
||||
|
import type { Accounts, Account } from 'types/common' |
||||
|
|
||||
|
type DateInterval = { |
||||
|
start: string, |
||||
|
end: string, |
||||
|
} |
||||
|
|
||||
|
type BalanceHistoryDay = { |
||||
|
date: string, |
||||
|
balance: number, |
||||
|
} |
||||
|
|
||||
|
// Map the given date interval
|
||||
|
// iteratee is given day, index, and currently constructed array
|
||||
|
// (exactly like Array.map)
|
||||
|
function mapInterval(iv: DateInterval, cb: Function) { |
||||
|
const res = [] |
||||
|
let startDate = moment(iv.start) |
||||
|
let i = 0 |
||||
|
const endDate = moment(iv.end) |
||||
|
res.push(cb(startDate.format('YYYY-MM-DD'), i, res)) |
||||
|
while (!startDate.isSame(endDate, 'day')) { |
||||
|
startDate = startDate.add(1, 'day') |
||||
|
res.push(cb(startDate.format('YYYY-MM-DD'), ++i, res)) |
||||
|
} |
||||
|
return res |
||||
|
} |
||||
|
|
||||
|
function getBalanceAtIntervalStart(account: Account, interval: DateInterval): number | null { |
||||
|
const target = moment(interval.start) |
||||
|
let res = 0 |
||||
|
for (const i in account.balanceByDay) { |
||||
|
if (account.balanceByDay.hasOwnProperty(i)) { |
||||
|
const d = moment(i) |
||||
|
if (!d.isBefore(target, 'day')) { |
||||
|
break |
||||
|
} |
||||
|
res = account.balanceByDay[i] || 0 |
||||
|
} |
||||
|
} |
||||
|
return res |
||||
|
} |
||||
|
|
||||
|
export function getBalanceHistoryForAccount({ |
||||
|
account, |
||||
|
fiat, |
||||
|
counterValues, |
||||
|
interval, |
||||
|
}: { |
||||
|
fiat: string, |
||||
|
account: Account, |
||||
|
counterValues: Object, |
||||
|
interval: DateInterval, |
||||
|
}): Array<BalanceHistoryDay> { |
||||
|
const unit = getDefaultUnitByCoinType(account.coinType) |
||||
|
const counterVals = counterValues[`${unit.code}-${fiat}`] |
||||
|
let lastBalance = getBalanceAtIntervalStart(account, interval) |
||||
|
return mapInterval(interval, date => { |
||||
|
let balance = 0 |
||||
|
|
||||
|
if (!counterVals) { |
||||
|
return { balance, date } |
||||
|
} |
||||
|
|
||||
|
// if we don't have data on account balance for that day,
|
||||
|
// we take the prev day
|
||||
|
if (isUndefined(account.balanceByDay[date])) { |
||||
|
balance = lastBalance === null ? 0 : lastBalance / 10 ** unit.magnitude * counterVals[date] |
||||
|
} else { |
||||
|
const b = account.balanceByDay[date] |
||||
|
lastBalance = b |
||||
|
balance = b / 10 ** unit.magnitude * counterVals[date] |
||||
|
} |
||||
|
|
||||
|
return { date, balance } |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export function getBalanceHistoryForAccounts({ |
||||
|
accounts, |
||||
|
fiat, |
||||
|
counterValues, |
||||
|
interval, |
||||
|
}: { |
||||
|
fiat: string, |
||||
|
accounts: Accounts, |
||||
|
counterValues: Object, |
||||
|
interval: DateInterval, |
||||
|
}): Array<BalanceHistoryDay> { |
||||
|
// calculate balance history for each account on the given interval
|
||||
|
const balances = accounts.map(account => |
||||
|
getBalanceHistoryForAccount({ |
||||
|
fiat, |
||||
|
account, |
||||
|
counterValues, |
||||
|
interval, |
||||
|
}), |
||||
|
) |
||||
|
|
||||
|
// if more than one account, addition all balances, day by day
|
||||
|
// and returns a big summed up array
|
||||
|
return balances.length > 1 |
||||
|
? balances[0].map((item, i) => { |
||||
|
let b = item.balance |
||||
|
for (let j = 1; j < balances.length; j++) { |
||||
|
b += balances[j][i].balance |
||||
|
} |
||||
|
return { ...item, balance: b } |
||||
|
}) |
||||
|
: balances.length > 0 ? balances[0] : [] |
||||
|
} |
Loading…
Reference in new issue