美文网首页
iOS/Swift: Markowitz Mean-Varia

iOS/Swift: Markowitz Mean-Varia

作者: 疯狂的向日葵 | 来源:发表于2017-01-12 11:00 被阅读172次

    版权声明:本文为博主原创文章,未经博主允许不得转载。

    Swift版:算法代码

    //
    //  ViewController.swift
    //  CalculatePortfolioComposition
    //
    //  Created by JimmyLaw on 2017/1/11.
    //  Copyright © 2017年 JimmyStudio. All rights reserved.
    //
    
    import UIKit
    import Surge
    
    class ViewController: UIViewController {
        
        // stock
        struct Stock {
            var name: String
            var code: String
            var dailyYield: [Double]
            var expect: Double
            var variance: Double = 0.0
            var percent: Double = 0.0
            init(name: String, code: String, dailyYield: [Double]) {
                self.name = name
                self.code = code
                self.dailyYield = dailyYield
                self.expect = mean(dailyYield)
            }
        }
        
        //result
        struct Result {
            var stocks: [Stock]
            var expect: Double
            var variance: Double
            var ev: Double
            var percents: [Double]
            init(stocks: [Stock], expect: Double, variance: Double, ev:Double,percents: [Double] ) {
                self.stocks = stocks
                self.expect = expect
                self.variance = variance
                self.ev = ev
                self.percents = percents
            }
            
            init(result: Result) {
                self.stocks = result.stocks
                self.expect = result.expect
                self.variance = result.variance
                self.ev = result.ev
                self.percents = result.percents
            }
        }
        
        struct MinAndMax {
            var min: Double = Double(MAXFLOAT)
            var max: Double = -(Double)(MAXFLOAT)
            init(exps: [Double]) {
                for exp in exps {
                    if exp >= max {
                        max = exp
                    }
                    if exp <= min {
                        min = exp
                    }
                }
            }
            
        }
        
        //creat stockData from CSV
        func ReadStockFile(fileName: String) -> [Stock] {
            var stocks = [Stock]()
    
            let filePath = Bundle.main.path(forResource: fileName, ofType: "csv")
            let fileUrl = URL.init(fileURLWithPath: filePath!)
            
            do{
                let content: String! = try String(contentsOf: fileUrl, encoding: String.Encoding.utf8)
                let r =  content.replacingOccurrences(of: "\r", with: "")
                let n =  r.replacingOccurrences(of: "\n", with: "")
                let arr = n.components(separatedBy: ",")
                for i in 0...9 {
                    
                    var name = ""
                    var code = ""
                    var yields = [Double]()
                    
                    for j in 0...29 {
                        if j == 0 {
                            name = arr[i + 10*j]
                        }else if j == 1{
                            code = arr[i + 10*j]
                        }else{
                            yields.insert((arr[i + 10*j] as NSString).doubleValue , at: yields.endIndex)
                        }
                    }
                    var s = Stock.init(name: name, code: code, dailyYield: yields)
                    s.variance = Variance(yields: yields)
                    stocks.insert(s, at: stocks.endIndex)
                }
                
                return stocks
            }catch{
                print("error")
                return stocks
            }
        }
        //simulate stocks
        var simulateStocks: [Stock]{
            
            return ReadStockFile(fileName: "stockData")
        }
        
        //计算期[Stock]的望值
        func Expects(stocks: [Stock]) -> [Double] {
            var output = [Double]()
            for stock in stocks {
                var exp: Double = 0.0
                for yield in stock.dailyYield {
                    exp += yield
                }
                let count: Double = Double(stock.dailyYield.count)
                output.insert(exp/count, at: output.endIndex)
            }
            return output
        }
        
        //计算方差
        func Variance(yields: [Double]) -> Double {
            let exp = mean(yields)
            var output = 0.0
            
            for yield in yields {
                output += pow((yield - exp), 2)
            }
            
            output /= Double(yields.count - 1)
            
            return output
        }
        
        //计算协方差
        func Eigen (stocks: [Stock]) -> [[Double]] {
            let exps = Expects(stocks: stocks)
            var output = [[Double]]()
            
            for i in 0...stocks.count - 1 {
                
                var cov_is = [Double]()
                let yield_i = stocks[i].dailyYield
    
                for j in 0...stocks.count - 1 {
                    
                    let yield_j = stocks[j].dailyYield
                    var cov_i: Double = 0.0
                    
                    for k in 0...yield_j.count - 1 {
                        cov_i += ((yield_i[k] - exps[i]) * (yield_j[k] - exps[j]))
                    }
                    cov_i /= (Double(yield_j.count - 1))
                    cov_is .insert(cov_i, at: cov_is.endIndex)
                }
                output .insert(cov_is, at: output.endIndex)
            }
        
            return output
        }
        
        var combines = [[Int]]()
        
        func Combine(arr: [Int], nLen: Int, m: Int, out: [Int], outLen: Int){
            var temp: [Int] = out
            
            if m == 0 {
                combines.insert(out, at: combines.endIndex)
                return
            }
            
            for i in (m...nLen).reversed() {
                temp.remove(at: m - 1)
                temp.insert(arr[i - 1], at: (m - 1))
                Combine(arr: arr, nLen: i - 1, m: m - 1, out: temp, outLen: outLen)
            }
        }
        
        
        func CalculateCombines(stocks: [Stock], num: Int) -> [[Stock]] {
            print("计算所有可能组合...\n")
            var arr = [Int]()
            var output = [[Stock]]()
            for i in 0...stocks.count - 1 {
                arr.insert(i, at: i)
            }
            
            let out = [Int](repeating: 0 , count: num)
            Combine(arr: arr, nLen: arr.count, m: num, out: out, outLen: num)
            print("合计\(combines.count)种成分配比...\n")
    
            print("组成所有可能成分配比...\n")
            for com in combines {
                var temp = [Stock]()
                for i in com {
                    temp.insert(stocks[i], at: temp.endIndex)
                }
                output.insert(temp, at: output.endIndex)
            }
            
            return output
        }
        
        var calculateTimes = 0
        
        func CalculateBestPercent(stocks: [Stock]) -> [Result]{
            
            var output = [Result]()
            
            let exps = Expects(stocks: stocks)
            
            let R_T = Matrix([exps])
            let R = transpose(R_T)
            let E_T = Matrix.init(rows: 1, columns: stocks.count, repeatedValue: 1.0) //(1,1...1)
            let E = Matrix.init(rows: stocks.count, columns: 1, repeatedValue: 1.0) //(1,1...1)T
            let V = Matrix(Eigen(stocks: stocks))
            let V_1 = inv(V)
            
            let A = (E_T * V_1 * R)[0,0]
            let B = (R_T * V_1 * R)[0,0]
            let C = (E_T * V_1 * E)[0,0]
            
            let D = B * C - A * A
            if D <= 0 {
                print("D < 0 无解\n")
                return output
                
            }else{
                print("D: ",D," 尝试计算最优解...")
                
                let D_1 = 1.0/D
                
                let B_V_1_E = B * V_1 * E
                let A_V_1_R = A * V_1 * R
                let B_V_1_E_A_V_1_R = sub(B_V_1_E[column: 0], y: A_V_1_R[column: 0])
                
                let g = mul(D_1, x: transpose(Matrix([B_V_1_E_A_V_1_R])))
                
                let C_V_1_R = C * V_1 * R
                let A_V_1_E = A * V_1 * E
                let C_V_1_R_A_V_1_E = sub(C_V_1_R[column: 0], y: A_V_1_E[column: 0])
                let h = mul(D_1, x: transpose(Matrix([C_V_1_R_A_V_1_E])))
                
                let mm = MinAndMax.init(exps: exps)
                let times = Int((mm.max - mm.min)*10000)
                
                if times <= 0 {
                    print("该组收益期望值过小!无解!\n")
                    return output
                }
                
                calculateTimes += times
                
                var i = mm.min
                for _ in 0...times {
                    
                    let W = g + mul(i, x: h)
                    let mi = min(W[column: 0])
                    let ma = max(W[column: 0])
                    
                    if i <= 0 {
                        print("期望收益 < 0 不再求解\n")
                        
                    }else if mi < 0.0 {
                        
                        print("组合中存在 < 0.00% 的配比,收益期望\(i)无解\n")
                        
                    }else if ma >= 0.9999 {
                        
                        print("组合中存在 >= 99.99% 的配比,收益期望\(i)无解\n")
                        print(ma)
                        
                    }else
                    {
                        print("=====组合收益期望\(i)有解=====\n")
    
                        let ex = R_T * W;//反算期望收益
                        let W_T = transpose(W);
                        let vari  = W_T * V * W
                        let ev = ex[0,0]/vari[0,0] //均值方差比
                        let result = Result.init(stocks: stocks, expect: ex[0,0], variance: vari[0,0], ev: ev, percents: W[column: 0])
                        output.insert(result, at: output.endIndex)
                    }
                    
                    i += 0.0001
                }
                return output
            }
        }
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            
            let combinesOfStock = CalculateCombines(stocks: simulateStocks, num: 5)
            
            var results = [Result]()
            
            for i in 0...combinesOfStock.count - 1 {
                print("计算第\(i + 1)种组合最优配比")
                let result = CalculateBestPercent(stocks: combinesOfStock[i])
                if (result.count > 0) {
                    print("第\(i + 1)组共\(result.count)组解")
                    for res in result {
                        results.insert(res, at: results.endIndex)
                    }
                }
            }
            
            
            print("**************结论**************\n")
            print("***********计算了\(calculateTimes)次***********\n")
            print("***********合计\(combines.count)种成分配比***********\n")
            print("***********共产生\(results.count)种组合***********\n")
            var evMax: Double = Double(-MAXFLOAT)
            var expMax: Double = Double(-MAXFLOAT)
            var varMin: Double = Double(MAXFLOAT)
    
            for i in 0...results.count - 1{
                if (results[i].ev >= evMax) {
                    evMax = results[i].ev
                }
                if results[i].expect >= expMax {
                    expMax = results[i].expect
                }
                if results[i].variance <= varMin {
                    varMin = results[i].variance
                }
            }
            
            for res in results{
                if res.ev == evMax {
                    print("******均值方差比最大的组合******")
                    print("期望收益率:\(res.expect)\n方差:\(res.variance)\n均值方差比:\(res.ev)")
                    print("配比:")
                    for i in 0...res.stocks.count - 1 {
                        print("名称: ",res.stocks[i].name,"代码: ",res.stocks[i].code,"配比: ",res.percents[i])
                    }
                    
                }
                if res.expect == expMax {
                    print("\n******期望收益率最大的组合******")
                    print("期望收益率:\(res.expect)\n方差:\(res.variance)\n均值方差比:\(res.ev)")
                    print("配比:")
                    for i in 0...res.stocks.count - 1 {
                        print("名称: ",res.stocks[i].name,"代码: ",res.stocks[i].code,"配比: ",res.percents[i])
                    }
                }
                if res.variance == varMin {
                    print("\n******方差最小的组合******")
                    print("期望收益率:\(res.expect)\n方差:\(res.variance)\n均值方差比:\(res.ev)")
                    print("配比:")
                    for i in 0...res.stocks.count - 1 {
                        print("名称: ",res.stocks[i].name,"代码: ",res.stocks[i].code,"配比: ",res.percents[i])
                    }
                }
            }
            
        }
        
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
        
        
    }
    

    任选10个股票的历史交易记录,任取其中4种股票,进行组合配比求解

    运算结果如下

    **************结论**************
    
    ***********计算了13248次***********
    
    ***********合计210种成分配比***********
    
    ***********共产生3097种组合***********
    
    
    ******方差最小的组合******
    期望收益率:2.00357142857126e-05
    方差:3.00676879937876e-06
    均值方差比:6.66353671418042
    配比:
    名称:  中来股份 代码:  300393 配比:  0.00414454618364605
    名称:  浪莎股份 代码:  600137 配比:  0.000805787492222925
    名称:  湖南天雁 代码:  600698 配比:  0.874775672115665
    名称:  信隆健康 代码:  002105 配比:  0.120273994208466
    
    ******均值方差之比最大的组合******
    期望收益率:0.000132885357142857
    方差:8.24153470892431e-06
    均值方差比:16.1238606444213
    配比:
    名称:  超讯通信 代码:  603322 配比:  0.00158115108426157
    名称:  新黄浦 代码:  600638 配比:  0.0133675998585093
    名称:  湖南天雁 代码:  600698 配比:  0.574677855077226
    名称:  信隆健康 代码:  002105 配比:  0.410373393980003
    
    ******期望收益率最大的组合******
    期望收益率:0.00672003571428572
    方差:0.00072940202654893
    均值方差比:9.21307518993426
    配比:
    名称:  光电股份 代码:  600184 配比:  0.00182208214544699
    名称:  中来股份 代码:  300393 配比:  0.0011345357693352
    名称:  新黄浦 代码:  600638 配比:  0.787917304207837
    名称:  能科股份 代码:  603859 配比:  0.20912607787738
    

    相关文章

      网友评论

          本文标题:iOS/Swift: Markowitz Mean-Varia

          本文链接:https://www.haomeiwen.com/subject/vqydbttx.html