美文网首页
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