iT邦幫忙

2021 iThome 鐵人賽

DAY 27
0
Mobile Development

使用 Swift 和公開資訊,打造投資理財的 Apps系列 第 28

D27 - 用 Swift 和公開資訊,打造投資理財的 Apps { 三大法人成交比重實作.2 }

先製作出簡單的一個 VC 上面顯示取得的三大法人資料的日期。

拉出兩個 Button、一個 state label、一個裝載 pie chart view 的 container view。

這邊需要了解三大法人成交金額的數據出來的時間,是在下午三點。而前面所做的每日市場成交資訊的公佈時間,並不一定和三大法人成交金額同時出來(詳細時間要測測看)。因為這樣的時間差,有可能在你滑進三大法人頁面時,取得的資料還在前一個交易日,但當下已經有現在交易日的台股總成交量金額。所以計算的時候,不可以拿最新的台股成交量當分母,一定要用拉取最新的三大法人資訊日期為 key,然後去查這個 key 的當日台股成交值是多少。

也因為有可能當下手機的時間和三大法人資料的日期不同,所以這個頁面最上方的 Label 是用來顯示資料的時間。

https://ithelp.ithome.com.tw/upload/images/20211007/20140622xoISUvENdo.png

資料的合併

從 csv 檔來的資料有下面這六項

    case dealersForProprietary //自營商自行買賣
    case dealersHedge//自營商(避險)
    case securitiesInvestorForTrust//投信
    case foreignInvestorWithoutForeignDealer // 外資及陸資不含外資自營商
    case foreignDealers //外資自營商
    case total //總計

但是,我們要的是[自營商]、[投信]、[外資]、[總計] 這四項而已,所以數據要處理。

宣告一個專門用於這個 pie chart 的 data model

/// 只有三大法人,沒有細項
enum ThreeMajorInvestorType {
    case dealers //自營商
    case securitiesInvestorForTrust //投信
    case foreign //外資
    case total //總計
}

class ThreeMajorInvestorInfo {
    
    let type : ThreeMajorInvestorType
    var totalBuy: Double = 0
    var totalSell: Double = 0
    var difference: Double = 0
    
    init(type: ThreeMajorInvestorType) {
        self.type = type
    }
    
    func getItemName() -> String {
        
        switch type {
        case .foreign:
            return "外資"
        case .dealers:
            return "自營"
        case .securitiesInvestorForTrust:
            return "投資"
        case .total:
            return "總合"
        }
    }
}

totalBuy, totalSell, difference 需要宣告成 var 的原因,是在合併的時候,我們要累加。

計算的 func 如下,在計算上,可以看到重複且類似的程式碼,這邊就讓讀都自行優化了

/// 取得三大法人 自營商的總和項目
    private func getDealerInfo(detailMajorInfos: [MajorInvestor]) -> ThreeMajorInvestorInfo {
        
        let info = ThreeMajorInvestorInfo(type: .dealers)
        
        for each in detailMajorInfos {
            
            // Dealer 自營商有兩項 1.自行買賣 2.避險
            if each.typeString.contains("Dealer") {
                
                info.totalBuy += each.totalBuy
                info.totalSell += each.totalSell
                info.difference += each.difference
            }
        }
        
        return info
    }
    
    /// 取得三大法人 投信的總和項目
    private func getSecuritiesTrustCompany(detailMajorInfos: [MajorInvestor]) -> ThreeMajorInvestorInfo {
        
        let info = ThreeMajorInvestorInfo(type: .securitiesInvestorForTrust)
        
        for each in detailMajorInfos {
            
            // 投信
            if each.typeString.contains("Securities") {
                
                info.totalBuy += each.totalBuy
                info.totalSell += each.totalSell
                info.difference += each.difference
            }
        }
        
        return info
    }
    
    /// 取得三大法人 外資的總和項目
    private func getForeignInvestor(detailMajorInfos: [MajorInvestor]) -> ThreeMajorInvestorInfo {
        
        let info = ThreeMajorInvestorInfo(type: .foreign)
        
        for each in detailMajorInfos {
            
            // 外資
            if each.typeString.contains("Foreign") {
                
                info.totalBuy += each.totalBuy
                info.totalSell += each.totalSell
                info.difference += each.difference
            }
        }
        
        return info
    }
    
    /// 取得三大法人 total 的項目
    private func getTotalInfo(detailMajorInfos: [MajorInvestor]) -> ThreeMajorInvestorInfo {
        
        let info = ThreeMajorInvestorInfo(type: .total)
        
        for each in detailMajorInfos {
            if each.typeString.contains("Total") {
                
                info.totalBuy = each.totalBuy
                info.totalSell = each.totalSell
                info.difference = each.difference
            }
        }
        
        return info
    }
    
    /// 這邊有可優化空間
    private func calculate(detailMajorInfos: [MajorInvestor]) -> TotalMajorInvestorInfo {
        
        let dealer = getDealerInfo(detailMajorInfos: detailMajorInfos)
        let securitiesTrustCompany = getSecuritiesTrustCompany(detailMajorInfos: detailMajorInfos)
        let foreign = getForeignInvestor(detailMajorInfos: detailMajorInfos)
        let total = getTotalInfo(detailMajorInfos: detailMajorInfos)
        
        let threeMajor = TotalMajorInvestorInfo(dealers: dealer, securitiesInvestorForTrust: securitiesTrustCompany, foreign: foreign, total: total)
        
        return threeMajor
    }

接著在 VC 加上一個 property

private var totalMajorInvestorInfo: TotalMajorInvestorInfo?

左邊的按鈕在計算完,把值賦於 totalMajorInvestorInfo

// MARK: - IBAction
    @IBAction func calculateButtonDidTap(_ sender: Any) {
        
        let threeMajorInvestors = calculate(detailMajorInfos: self.majorInvestors)
        self.totalMajorInvestorInfo = threeMajorInvestors
        
    }

可以再順手做一下三大法人進出總金額的計算,並把結果放在 UI 上

private func updateCalculateUI() {
        
        var text = "計算完畢  "
        
        let unit = 100_000_000 //億
        
        if let total = totalMajorInvestorInfo?.total {
            
            let item = total.getItemName()
            
            let buy = Int(total.totalBuy) / unit
            
            let sell = Int(total.totalSell) / unit
            
            let diff = Int(total.difference) / unit
            
            text += " \(item): - 買進:\(buy) 億, 賣出:\(sell) 億, 買賣差:\(diff) 億,"
        }
        
        calculateLabel.text = text
    }

那 button 發動的程式碼如下

// MARK: - IBAction
    @IBAction func calculateButtonDidTap(_ sender: Any) {
        
        let threeMajorInvestors = calculate(detailMajorInfos: self.majorInvestors)
        self.totalMajorInvestorInfo = threeMajorInvestors
        
        updateCalculateUI() // 和前面的 button 程式碼比起來,只差這一行
    }

上一篇
D26 - 用 Swift 和公開資訊,打造投資理財的 Apps { 三大法人成交比重實作.1 }
下一篇
D28 - 用 Swift 和公開資訊,打造投資理財的 Apps { 三大法人成交比重實作.3 }
系列文
使用 Swift 和公開資訊,打造投資理財的 Apps37
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言