Skip to content

Commit

Permalink
Merge develop to master (#26)
Browse files Browse the repository at this point in the history
* Add Amount and extensions to calculate totals and averages

* Add test cases for Linux

* Add conformances to Hashable, Comparable, Equatable

* Rename stocks to holdings on Portfolio

* Allow setting a Target Price on a Stock

* Use UInt64 for market cap and volume on a Stock

* Make types properly conform to Equatable

* Remove precondition that CurrencyPair rate should be above 0

* Ignore .build folder

* Autogenerate XCTestManifests and LinuxMain

* Add functions to Portfolio to get total value, cost and change of multiple portfolios

* Conform CurrencyPair to Equatable, Hashable and Codable

* Exclude XCTestManifests from Swiftlint

* Add conformance to Comparable for Transaction

* Add Amount

* Sort transactions by date before building holdings

* Add simple Dividend model

* Add Dividend initializer

* Add intrinsic value property to Stock

* Change type for Stock last traded

* Add accumulated dividend and ownership for Holdings

* Fix swiftlint warnings

Co-authored-by: Christian Mitteldorf <christian@mitteldorf.dk>
  • Loading branch information
christiankm and christiankm committed Apr 1, 2020
1 parent 2fcf2f7 commit ec472d5
Show file tree
Hide file tree
Showing 22 changed files with 130 additions and 28 deletions.
4 changes: 3 additions & 1 deletion .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ opt_in_rules:
# Configure Rules
force_unwrapping:
severity: error
line_length:
warning: 140
overridden_super_call:
severity: error
prohibited_super_call:
Expand All @@ -68,7 +70,7 @@ file_header:
\/\/ FinanceKit
\/\/
\/\/ Created by .*? on \d{1,2}\/\d{1,2}\/\d{2}\.
\/\/ Copyright © \d{4} Mitteldorf\. All rights reserved\.
\/\/ Copyright © 2020 Mitteldorf\. All rights reserved\.
\/\/
custom_rules:
Expand Down
31 changes: 29 additions & 2 deletions FinanceKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@
AA06F78523D9EEBB001FFAE9 /* CurrencyPair.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA06F78423D9EEBB001FFAE9 /* CurrencyPair.swift */; };
AA06F78723D9F06A001FFAE9 /* CurrencyPairTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA06F78623D9F06A001FFAE9 /* CurrencyPairTests.swift */; };
AA06F78B23D9F987001FFAE9 /* CompanyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA06F78A23D9F987001FFAE9 /* CompanyTests.swift */; };
AA601F7223DDF37A008E94C6 /* StockTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA601F5023DDF37A008E94C6 /* StockTests.swift */; };
AA339E682403056C005D5CA8 /* Amount.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA339E552403056B005D5CA8 /* Amount.swift */; };
AA339E772403056D005D5CA8 /* Numerics+Total+Average.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA339E642403056C005D5CA8 /* Numerics+Total+Average.swift */; };
AA5E80CD2434F9BE001B1E16 /* Dividend.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA5E80CB2434F9BE001B1E16 /* Dividend.swift */; };
AA5E80CE2434F9BE001B1E16 /* PriceTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA5E80CC2434F9BE001B1E16 /* PriceTarget.swift */; };
AA601F7223DDF37A008E94C6 /* StockTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA601F5023DDF37A008E94C6 /* StockTests.swift */; };
AA69850C23760EFC00D0683C /* Decimal+DoubleValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA69850823760EFC00D0683C /* Decimal+DoubleValue.swift */; };
AA69851D2377351800D0683C /* SymbolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA69851C2377351800D0683C /* SymbolTests.swift */; };
AA7A62B123E5D3F20094DC2B /* Exchange.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA7A62B023E5D3F20094DC2B /* Exchange.swift */; };
Expand Down Expand Up @@ -74,9 +76,11 @@
AA06F78623D9F06A001FFAE9 /* CurrencyPairTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrencyPairTests.swift; sourceTree = "<group>"; };
AA06F78823D9F83F001FFAE9 /* PortfolioTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PortfolioTests.swift; sourceTree = "<group>"; };
AA06F78A23D9F987001FFAE9 /* CompanyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompanyTests.swift; sourceTree = "<group>"; };
AA601F5023DDF37A008E94C6 /* StockTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StockTests.swift; sourceTree = "<group>"; };
AA339E552403056B005D5CA8 /* Amount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Amount.swift; sourceTree = "<group>"; };
AA339E642403056C005D5CA8 /* Numerics+Total+Average.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Numerics+Total+Average.swift"; sourceTree = "<group>"; };
AA5E80CB2434F9BE001B1E16 /* Dividend.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Dividend.swift; sourceTree = "<group>"; };
AA5E80CC2434F9BE001B1E16 /* PriceTarget.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PriceTarget.swift; sourceTree = "<group>"; };
AA601F5023DDF37A008E94C6 /* StockTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StockTests.swift; sourceTree = "<group>"; };
AA69850523760EF000D0683C /* FinanceKit.xctestplan */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = FinanceKit.xctestplan; sourceTree = "<group>"; };
AA69850823760EFC00D0683C /* Decimal+DoubleValue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Decimal+DoubleValue.swift"; sourceTree = "<group>"; };
AA69851C2377351800D0683C /* SymbolTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SymbolTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -193,11 +197,13 @@
AA7DA6F02391DA4400EF65F5 /* CurrencyCode.swift */,
AA06F78423D9EEBB001FFAE9 /* CurrencyPair.swift */,
AA69850823760EFC00D0683C /* Decimal+DoubleValue.swift */,
AA5E80CB2434F9BE001B1E16 /* Dividend.swift */,
AA7A62B023E5D3F20094DC2B /* Exchange.swift */,
AAE67784239298550053B303 /* Holding.swift */,
AA339E642403056C005D5CA8 /* Numerics+Total+Average.swift */,
OBJ_30 /* Portfolio.swift */,
OBJ_31 /* Price.swift */,
AA5E80CC2434F9BE001B1E16 /* PriceTarget.swift */,
AAE677822392979A0053B303 /* Quantity.swift */,
OBJ_35 /* Stock.swift */,
OBJ_44 /* Symbol.swift */,
Expand All @@ -218,6 +224,7 @@
OBJ_131 /* Frameworks */,
AA55AA75231ADE430073725E /* Run Swiftlint */,
AA9F511323E327B700A8107B /* Run Pecker */,
AA7969A8241CC8C600759CC8 /* Generate XCTestManifest and LinuxMain */,
);
buildRules = (
);
Expand Down Expand Up @@ -308,6 +315,24 @@
shellPath = /bin/sh;
shellScript = "if which swiftlint >/dev/null; then\n swiftlint autocorrect && swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
};
AA7969A8241CC8C600759CC8 /* Generate XCTestManifest and LinuxMain */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Generate XCTestManifest and LinuxMain";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "swift test --generate-linuxmain\n";
};
AA9F511323E327B700A8107B /* Run Pecker */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
Expand Down Expand Up @@ -359,6 +384,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 0;
files = (
AA5E80CD2434F9BE001B1E16 /* Dividend.swift in Sources */,
OBJ_88 /* Change.swift in Sources */,
OBJ_89 /* Company.swift in Sources */,
AA06F78523D9EEBB001FFAE9 /* CurrencyPair.swift in Sources */,
Expand All @@ -372,6 +398,7 @@
AA339E772403056D005D5CA8 /* Numerics+Total+Average.swift in Sources */,
AAE677832392979A0053B303 /* Quantity.swift in Sources */,
AA7DA6F12391DA4400EF65F5 /* CurrencyCode.swift in Sources */,
AA5E80CE2434F9BE001B1E16 /* PriceTarget.swift in Sources */,
OBJ_123 /* Symbol.swift in Sources */,
AA69850C23760EFC00D0683C /* Decimal+DoubleValue.swift in Sources */,
OBJ_126 /* Transaction.swift in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion Sources/FinanceKit/Change.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// FinanceKit
//
// Created by Christian Mitteldorf on 05/08/2017.
// Copyright © 2019 Mitteldorf. All rights reserved.
// Copyright © 2020 Mitteldorf. All rights reserved.
//

import Foundation
Expand Down
2 changes: 1 addition & 1 deletion Sources/FinanceKit/Currency.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// FinanceKit
//
// Created by Christian Mitteldorf on 17/05/2017.
// Copyright © 2017 Mitteldorf. All rights reserved.
// Copyright © 2020 Mitteldorf. All rights reserved.
//

import Foundation
Expand Down
1 change: 1 addition & 0 deletions Sources/FinanceKit/CurrencyCode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// FinanceKit
//
// Created by Christian Mitteldorf on 29/11/2019.
// Copyright © 2020 Mitteldorf. All rights reserved.
//

import Foundation
Expand Down
1 change: 1 addition & 0 deletions Sources/FinanceKit/Decimal+DoubleValue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// FinanceKit
//
// Created by Christian Mitteldorf on 07/11/2019.
// Copyright © 2020 Mitteldorf. All rights reserved.
//

import Foundation
Expand Down
19 changes: 19 additions & 0 deletions Sources/FinanceKit/Dividend.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// Dividend.swift
// FinanceKit
//
// Created by Christian Mitteldorf on 05/08/2017.
//

import Foundation

public struct Dividend: Hashable, Identifiable, Equatable {
public let id = UUID()
public let symbol: Symbol
public var value: Amount = 0

public init(symbol: Symbol, value: Amount = 0) {
self.symbol = symbol
self.value = value
}
}
4 changes: 2 additions & 2 deletions Sources/FinanceKit/Exchange.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
// FinanceKit
//
// Created by Christian Mitteldorf on 10/01/2020.
// Copyright © 2017 Christian Mitteldorf. All rights reserved.
// Copyright © 2020 Mitteldorf. All rights reserved.
//

import Foundation

public struct Exchange: Codable, Equatable {

public let symbol: String
public let name: String

Expand Down
21 changes: 16 additions & 5 deletions Sources/FinanceKit/Holding.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// FinanceKit
//
// Created by Christian Mitteldorf on 28/10/2019.
// Copyright © 2019 Mitteldorf. All rights reserved.
// Copyright © 2020 Mitteldorf. All rights reserved.
//

import Foundation
Expand All @@ -15,6 +15,7 @@ public struct Holding: Identifiable, Hashable, Equatable, Codable {

public let symbol: Symbol

public var stock: Stock?
public var company: Company?

public var quantity: Quantity
Expand All @@ -30,8 +31,6 @@ public struct Holding: Identifiable, Hashable, Equatable, Codable {
costBasis / Decimal(quantity)
}

public var stock: Stock?

public var averageAdjustedCostBasisPerShare: Decimal = 0
public var accumulatedDividends: Decimal = 0

Expand All @@ -42,6 +41,12 @@ public struct Holding: Identifiable, Hashable, Equatable, Codable {
public var currentValue: Price
public var currentValueInLocalCurrency: Price

/// Returns the ownership in terms of percentage of the total amount of oustanding shares.
public var ownership: Double {
guard let outstandingShares = stock?.shares, outstandingShares > 0 else { return 0 }
return Double(quantity / Int(outstandingShares))
}

public init(symbol: Symbol, quantity: Quantity = 0, costBasis: Price = 0,
costBasisInLocalCurrency: Price = 0, currentValue: Price = 0,
currentValueInLocalCurrency: Price = 0) {
Expand All @@ -66,8 +71,12 @@ public struct Holding: Identifiable, Hashable, Equatable, Codable {
return []
}

// Sort transactions by date to be sure they are
// processed in the real-time order.
let sortedTransactions = transactions.sorted()

var holdings: [Holding] = []
transactions.forEach { transaction in
sortedTransactions.forEach { transaction in
let symbol = transaction.symbol
let quantity = transaction.quantity
let price = transaction.price
Expand All @@ -87,6 +96,7 @@ public struct Holding: Identifiable, Hashable, Equatable, Codable {
holding.costBasis -= costBasis
case .dividend:
holding.costBasis -= costBasis
holding.accumulatedDividends += transaction.totalDividend
}

// Remove previous and re-add newly calculated holding
Expand All @@ -103,7 +113,7 @@ public struct Holding: Identifiable, Hashable, Equatable, Codable {
case .sell:
break
case .dividend:
break
holding.accumulatedDividends = transaction.totalDividend
}

holdings.append(holding)
Expand All @@ -125,6 +135,7 @@ public struct Holding: Identifiable, Hashable, Equatable, Codable {
public mutating func update(with stock: Stock) -> Holding {
guard stock.symbol == symbol else { return self }

self.stock = stock
company = stock.company
currentValue = stock.price * Decimal(quantity)

Expand Down
2 changes: 2 additions & 0 deletions Sources/FinanceKit/Numerics+Total+Average.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
//swiftlint:disable:this file_name
//
// Numerics+Total+Average.swift
// FinanceKit
//
// Created by Christian Mitteldorf on 11/02/2020.
// Copyright © 2020 Mitteldorf. All rights reserved.
//

import Foundation
Expand Down
6 changes: 3 additions & 3 deletions Sources/FinanceKit/Portfolio.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// FinanceKit
//
// Created by Christian Mitteldorf on 15/09/2019.
// Copyright © 2017 Christian Mitteldorf. All rights reserved.
// Copyright © 2020 Mitteldorf. All rights reserved.
//

import Foundation
Expand Down Expand Up @@ -84,8 +84,8 @@ public struct Portfolio: Codable, Hashable, Identifiable {

public static func totalChangeInLocalCurrency(of portfolios: [Portfolio]) -> Change {
guard !portfolios.isEmpty else { return .zero }
let averageCost: Amount = portfolios.reduce(0) { $0 + $1.costBasisInLocalCurrency } / Decimal(portfolios.count)
let averageValue: Amount = portfolios.reduce(0) { $0 + $1.currentValueInLocalCurrency } / Decimal(portfolios.count)
let averageCost = portfolios.reduce(0) { $0 + $1.costBasisInLocalCurrency } / Decimal(portfolios.count)
let averageValue = portfolios.reduce(0) { $0 + $1.currentValueInLocalCurrency } / Decimal(portfolios.count)

return Change(cost: averageCost, currentValue: averageValue)
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/FinanceKit/Price.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// FinanceKit
//
// Created by Christian Mitteldorf on 21/07/2019.
// Copyright © 2019 Mitteldorf. All rights reserved.
// Copyright © 2020 Mitteldorf. All rights reserved.
//

import Foundation
Expand Down
1 change: 1 addition & 0 deletions Sources/FinanceKit/PriceTarget.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// FinanceKit
//
// Created by Christian Mitteldorf on 12/02/2020.
// Copyright © 2020 Mitteldorf. All rights reserved.
//

import Foundation
Expand Down
1 change: 1 addition & 0 deletions Sources/FinanceKit/Quantity.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// FinanceKit
//
// Created by Christian Mitteldorf on 08/11/2019.
// Copyright © 2020 Mitteldorf. All rights reserved.
//

import Foundation
Expand Down
10 changes: 6 additions & 4 deletions Sources/FinanceKit/Stock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// FinanceKit
//
// Created by Christian Mitteldorf on 17/05/2017.
// Copyright © 2017 Christian Mitteldorf. All rights reserved.
// Copyright © 2020 Mitteldorf. All rights reserved.
//

import Foundation
Expand All @@ -30,11 +30,13 @@ public struct Stock: Identifiable, Equatable, Codable {
public var timezone: String?
public var timezoneName: String?
public var gmtOffset: String?
public var lastTradeTime: String?
public var pe: Double?
public var eps: Decimal?
public var lastTraded: Date?
public var priceEarnings: Double?
public var earningsPerShare: Amount?

public var target: PriceTarget?
public var intrinsicValue: PriceTarget?

public init(symbol: Symbol, company: Company, price: Decimal, currency: Currency,
marketCap: UInt64? = nil, exchange: Exchange? = nil, change: Change? = nil) {
self.symbol = symbol
Expand Down
7 changes: 6 additions & 1 deletion Sources/FinanceKit/Transaction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// FinanceKit
//
// Created by Christian Mitteldorf on 19/10/2019.
// Copyright © 2019 Mitteldorf. All rights reserved.
// Copyright © 2020 Mitteldorf. All rights reserved.
//

import Foundation
Expand Down Expand Up @@ -38,6 +38,11 @@ public struct Transaction: Codable, Hashable {
return cost
}

public var totalDividend: Amount {
guard type == .dividend else { return 0 }
return price * Decimal(quantity)
}

public init(type: TransactionType, symbol: Symbol, date: Date,
price: Price, quantity: Quantity, commission: Price = 0) {
self.type = type
Expand Down
2 changes: 1 addition & 1 deletion Tests/FinanceKitTests/ChangeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// FinanceKit
//
// Created by Christian Mitteldorf on 04/09/2019.
// Copyright © 2019 Christian Mitteldorf. All rights reserved.
// Copyright © 2020 Mitteldorf. All rights reserved.
//

import XCTest
Expand Down
2 changes: 1 addition & 1 deletion Tests/FinanceKitTests/CurrencyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// FinanceKit
//
// Created by Christian Mitteldorf on 29/11/2019.
// Copyright © 2019 Mitteldorf. All rights reserved.
// Copyright © 2020 Mitteldorf. All rights reserved.
//

import XCTest
Expand Down
Loading

0 comments on commit ec472d5

Please sign in to comment.