Reputation: 11175
I'm creating a cryptocurrency price tracking app which has a chart to illustrate the value of a portfolio over the past 7 days. As such, I need a way to generate the data points on the chart.
For each cryptocurrency in a portfolio, I have an array of NSDecimalNumber
values which represent the price of the cryptocurrency at each hour in the past week. To create the data points, I need a way to calculate an overall weighted average of the hourly prices. By weighted, I mean that the overall average array should represent the amount of each cryptocurrency currently held.
For example, if I have the following arrays:
Cryptocurrency 1 (25% of the overall portfolio value) - [1.2, 8.3, 7.2]
Cryptocurrency 2 (25% of the overall portfolio value) - [3.4, 9.2, 6.3]
Cryptocurrency 3 (50% of the overall portfolio value) - [6.3, 1.1, 5.9]
The result should be:
[4.3, 4.92, 6.33]
As a result of the calculations:
((1.2 * 0.75) + (3.4 * 0.75) + (6.3 * 1.5)) / 3 = 4.3
((8.3 * 0.75) + (9.2 * 0.75) + (1.1 * 1.5)) / 3 = 4.92
((7.2 * 0.75) + (6.3 * 0.75) + (5.9 * 1.5)) / 3 = 6.33
I'm certain there must be a clean way to do this with map
and reduce
, however I haven't yet thought of any potential solutions. Even a loop-based answer would be appreciated, as I can streamline it later.
Upvotes: 1
Views: 91
Reputation: 11175
If anyone is curious, this is what I ended up with based on qtngo's answer:
let holdings = cryptocurrencies.flatMap { cryptocurrency -> (cryptocurrency: Cryptocurrency, assetHolding: AssetHolding)? in
guard let assetHolding = portfolio.assetHolding(forCryptocurrency: cryptocurrency) else {
return nil
}
return (cryptocurrency, assetHolding)
}
let sparklineLength = holdings.map { $0.cryptocurrency.marketOverview.sparkline.count }.min() ?? 0
let weights = holdings.flatMap { holding -> NSDecimalNumber in
let quantity = NSDecimalNumber(value: holding.assetHolding.quantity)
let value = holding.cryptocurrency.marketOverview.valuation.value
let totalHoldingValue = value.multiplying(by: quantity)
let totalPortfolioValue = portfolio.totalValue(withCryptocurrencies: cryptocurrencies)
let percentage = totalHoldingValue.dividing(by: totalPortfolioValue)
return percentage
}
var averageSparkline = [NSDecimalNumber]()
for index in 0..<sparklineLength {
let indexSparklineValues = holdings.flatMap { holding -> NSDecimalNumber? in
return holding.cryptocurrency.marketOverview.sparkline[index]
}
let averageSparklineValue = zip(indexSparklineValues, weights).map { $0.multiplying(by: $1) }.reduce(0, +)
averageSparkline.append(averageSparklineValue)
}
It needs some tidying up and can probably be simplified but it produces the result I was looking for.
Upvotes: 0
Reputation: 1679
You can try this code:
let weight = [0.25, 0.25, 0.5]// Weights of your crypto, matrix 1*N
let crypto1 = [1.2, 8.3, 7.2]
let crypto2 = [3.4, 9.2, 6.3]
let crypto3 = [6.3, 1.1, 5.9]
let crypto = [crypto1, crypto2, crypto3]// Matrix M*N
var result: [Double] = []
for i in 0..<weight.count {
let aux = crypto.map { $0[i] }
let sum = zip(aux, weight).map { $0 * $1 }.reduce(0,+)
result.append(sum)
}
print("test: \(result)") // print "test: [4.3, 4.925, 6.325]"
Hope this helps.
Upvotes: 1