美股記帳 App / Part 3 均價獲利計算 & Charts 製作圖表分析

Julia
彼得潘的 Swift iOS / Flutter App 開發教室
9 min readMar 21, 2022

功能:

  • Average Price, Average Dollar Cost, Earning, Money Balance
  • 以個股獲利所製作的 Pie Chart

報表內容

  • totalQuantity : 股票總共的張數
  • totalDollarCost : 每次交易的金錢總和 (money balance)
  • AverageDollarCost :totalDollarCost / totalQuantity * -1
  • AveragePrice :現有股票的均價
  • preAveragePrice :前一次的均價,方便計算 AveragePriceChange 和 AveragePriceChangePercentage
  • Earning: 每一次賣掉股票時,依 AveragePrice 所算的獲利
struct stockStatistics : Codable{
let stockSymbol : String
var totalQuantity : Double
var totalDollarCost : Double
var AverageDollarCost : Double{
if totalQuantity == 0{
return 0
}else{
return totalDollarCost / totalQuantity * -1.0
}
}

var AveragePrice: Double
var prevAveragePrice : Double
var AveragePriceChange : Double{
return AveragePrice - prevAveragePrice
}
var AveragePriceChangePercentage : Double{
if prevAveragePrice == 0 {
return 0
}
return AveragePriceChange / prevAveragePrice
}

var earning : Double
var earningChange : Double
}

均價算法

  • 按時間由早到晚重新將 transactionRecords 排序
  • 透過 for loop 跑過每一個 transaction
  • 第一筆交易時,AveragePrice 為購買股票的價格
  • 買進股票時,AveragePrice 為 ( 買進之前的 AveragePrice 乘以 買進之前的總張數 加上 這次買進的股票價格 乘以 這次買進的張數)除以 買進的總張數
  • 賣掉股票時,AveragePrice 不變,Earning 為 (賣掉股價 減 AveragePrice ) 乘以 賣掉股票的張數
  • 經過測試,在股票全部賣掉後,用 AveragePrice 計算的 Earning 會和 Money Balance 一樣,代表這個算法是可行的喔!!!

Pie Chart

1.下載第三方套件 Charts 並安裝

2. 設定 Entry

  • Entry : data value
  • 使用 map 取出 symbolStock 當 pie chart 的label,並通過 function 得到該股票的 earning 當 pie chart 的 value
func getEarning(stockSymbol : String) -> Double{

if let index = stockStatisticsList.firstIndex(where: {$0.stockSymbol == stockSymbol}){
return stockStatisticsList[index].earning
}
return 0
}
let pieChartDataEntries = symbolList.map({(symbol) -> PieChartDataEntry in
return PieChartDataEntry(value: getEarning(stockSymbol: symbol), label:symbol)
})

3. 設定 dataSet

  • dataSet : 設定 entry 要展現的設定
  • selectionShift : 選中的 pie 會往外移多少
  • sliceSpace:每個 pie 之間的縫隙
  • color : pie 的顏色,因為股票的數量每次可能都不一樣,所以選擇 chartColorTemplates 裡配好的一系列顏色
let pieChartDataSet = PieChartDataSet(entries: pieChartDataEntries, label: "")pieChartDataSet.selectionShift = 10
pieChartDataSet.sliceSpace = 2

pieChartDataSet.colors = ChartColorTemplates.pastel() + ChartColorTemplates.material()

4. 設定 data

  • data : 設定 entry 裡 value 呈現的方式
  • setValueFormatter 裡的 input 要遵從 NSObject, protocol: ValueFormatter 所以要額外寫一個 class
let pieChartData = PieChartData(dataSet: pieChartDataSet)

pieChartData.setValueFormatter(percentageValueFormatter())
pieChartData.setValueFont(.systemFont(ofSize: 12, weight: .regular))
pieChartData.setValueTextColor(.white)

class percentageValueFormatter : NSObject,ValueFormatter{
func stringForValue(_ value: Double, entry: ChartDataEntry, dataSetIndex: Int, viewPortHandler: ViewPortHandler?) -> String {
return String(format: "%.1f%%", value)
}
}

5. 設定 chartView

  • usePerventValuesEnabled : 讓資料以百分比呈現
  • animate : 顯示圖的動畫
  • sliceTextDrawingThreshold : 如果 pie小於設定的 degree ,pie 裡就不會有文字 (怕 pie 太小,字全都擠在一起)
pieChartView.data = pieChartDatapieChartView.usePercentValuesEnabled = truepieChartView.animate(xAxisDuration: 1.0, yAxisDuration: 1.0)pieChartView.sliceTextDrawingThreshold = 20

6. 設定 legend

let legend = pieChartView.legend
legend.horizontalAlignment = .center
legend.verticalAlignment = .bottom
legend.orientation = .horizontal
legend.textColor = .white
legend.font = UIFont.systemFont(ofSize: 12)
legend.form = .circle
legend.formToTextSpace = 4
legend.formSize = 10

7. 設定 pie chart 中間的字

let totalEarning = stockStatisticsList.reduce(0.0, {$0 + $1.earning})pieChartView.centerText = "Total Earning :\n \(totalEarning.getCurrencyFormat())"

Github:

Link:

--

--