Skip to content

Commit

Permalink
Fix issues with using instance instead of type for USD, etc. (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
ScottPJones authored Jun 29, 2020
1 parent 1db8118 commit 6574b16
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 52 deletions.
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
*.jl.cov
*.jl.*.cov
*.jl.mem
Manifest.toml
**/*.log
**/*.json
**/*.json
.DS_Store
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ FixedPointDecimals = "fb4d412d-6eee-574d-9565-ede6634db7b0"
Instruments = "2a4f3d17-849a-48a1-809e-d780c70a95a0"

[compat]
Currencies = "0.17"
Instruments = "0.6"
Currencies = ">= 0.17"
Instruments = ">= 0.7"

[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Expand Down
36 changes: 28 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,32 @@
# Assets

# Assets

[pkg-url]: https://github.com/JuliaFinance/Assets.jl.git

[julia-url]: https://github.com/JuliaLang/Julia
[julia-release]:https://img.shields.io/github/release/JuliaLang/julia.svg

[release]: https://img.shields.io/github/release/JuliaFinance/Assets.jl.svg
[release-date]: https://img.shields.io/github/release-date/JuliaFinance/Assets.jl.svg

[license-img]: http://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat
[license-url]: LICENSE.md
[travis-url]: https://travis-ci.org/JuliaFinance/Assets.jl
[travis-s-img]: https://travis-ci.org/JuliaFinance/Assets.jl.svg
[travis-m-img]: https://travis-ci.org/JuliaFinance/Assets.jl.svg?branch=main

[![][travis-s-img]][travis-url] [![][travis-m-img]][travis-url]
[contrib]: https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat

[codecov-url]: https://codecov.io/gh/JuliaFinance/Assets.jl
[codecov-img]: https://codecov.io/gh/JuliaFinance/Assets.jl/branch/master/graph/badge.svg

[![][release]][pkg-url] [![][release-date]][pkg-url] [![][license-img]][license-url] [![contributions welcome][contrib]](https://github.com/JuliaFinance/Assets.jl/issues)

| **Julia Version** | **Unit Tests** | **Coverage** |
|:------------------:|:------------------:|:---------------------:|:---------------------:|
| [![][julia-release]][julia-url] | [![][travis-s-img]][travis-url] | [![][codecov-img]][codecov-url]
| Julia Latest | [![][travis-m-img]][travis-url] | [![][codecov-img]][codecov-url]

This package provides concrete implementations of `Instrument` for various financial assets:

Expand All @@ -19,20 +39,20 @@ It also provides a specialized `Position` for `Cash` that uses the currency's mi

When a currency is thought of as a financial instrument (as opposed to a mere label), we choose to refer to it as "Cash" as it would appear in a balance sheet. This package implements the `Cash` instrument with parameter `S` being the 3-character ISO 4217 alpha label of the currency as a `Symbol` and an integer `N` representing the number of decimal places in the currency (typically 0, 2 or 3).

Short constants are set up, matching the ISO 4217 names, so that you can use `USD` instead of `Cash{:USD,2}()`.
Short constants are set up, matching the ISO 4217 names, so that you can use `USD` instead of `Cash{:USD,2}`.

For example:

```julia
julia> import Assets: JPY, USD, JOD
julia> using Assets: JPY, USD, JOD

julia> typeof(JPY)
julia> JPY
Cash{:JPY,0}

julia> typeof(USD)
julia> USD
Cash{:USD,2}

julia> typeof(JOD)
julia> JOD
Cash{:JOD,3}
```

Expand All @@ -47,7 +67,7 @@ Although `Cash` is a singleton type, other financial instruments may contain var
A `Position` represents an amount of ownership of a financial instrument. For example, Microsoft stock

```julia
const MSFT = Stock(:MSFT,:USD)
const MSFT = stock(:MSFT,:USD)
```
is a financial instrument. A position could be 1,000 shares of `MSFT` and can be represented in one of two ways:

Expand Down Expand Up @@ -114,4 +134,4 @@ Algebraic operations on positions require the positions to be of the same instru
For more information, see

- [Currencies.jl](https://github.com/JuliaFinance/Currencies.jl.git)
- [Ledgers.jl](https://github.com/JuliaFinance/Ledgers.jl.git)
- [Ledgers.jl](https://github.com/JuliaFinance/Ledgers.jl.git)
54 changes: 34 additions & 20 deletions src/Assets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This package provides implementations of `Instrument` for various financial asse
- `Cash`: which is based on a particular currency type, along with the minor unit.
- `Stock`: which represents a general common stock.
It also provides a specialized `Position` for `Cash` that uses the currency's minor unit.
It also provides a specialized `Position` for `Cash that uses the currency's minor unit.
See README.md for the full documentation
Expand All @@ -19,28 +19,33 @@ module Assets
using Currencies, FixedPointDecimals, Instruments
import Currencies: symbol, currency, unit, code, name

export Cash, Stock, @cash_str, @stock_str
export Cash, Stock, cash, stock, @cash_str, @stock_str

"""
`Cash` is an implementation of `Instrument` represented by a singleton type with its currency symbol and the number of digits in the minor units, typically 0, 2, or 3, as parameters.
`Cash` is an implementation of `Instrument` represented by a singleton type,
with its currency symbol and the number of digits in the minor units,
typically 0, 2, or 3, as parameters.
"""
struct Cash{S, N} <: Instrument{S,Currency{S}}
function Cash{S,N}() where {S,N}
unit(S) === N || error("Currency minor unit does not match.")
new{S,N}()
end
end
Cash(S::Symbol) = Cash{S,unit(S)}()
Cash(::Type{Currency{S}}) where {S} = Cash(S)
Cash(::Currency{S}) where {S} = Cash(S)

unit(::Cash{S,N}) where {S,N} = N
code(::Cash{S}) where {S} = code(S)
name(::Cash{S}) where {S} = name(S)
currency(::Cash{S}) where {S} = currency(S)
# Functions to return the types, not instances, with the constructors
cash(S::Symbol) = Cash{S,unit(S)}
cash(::Type{Currency{S}}) where {S} = cash(S)

# Handle using the type instead of an instance for Cash
symbol(::Type{<:Cash{S}}) where {S} = S
unit(::Type{Cash{S,N}}) where {S,N} = N
code(::Type{<:Cash{S}}) where {S} = code(S)
name(::Type{<:Cash{S}}) where {S} = name(S)
currency(::Type{<:Cash{S}}) where {S} = currency(S)

macro cash_str(str)
:( Stock(Symbol($(esc(str)))) )
:( cash(Symbol($(esc(str)))) )
end

function Position{Cash{C,N}}(a) where {C,N}
Expand All @@ -49,21 +54,30 @@ function Position{Cash{C,N}}(a) where {C,N}
end

"""
`Stock` is an implementation of a simple `Instrument` represented by a singleton type with a stock symbol and currency, e.g. `Stock{:MSFT,:USD}`. The currency can be omitted and it will default to USD, e.g. `Stock(:MSFT)`.
`Stock` is an implementation of a simple `Instrument` represented by a singleton type
with a stock symbol and currency, e.g. `Stock{:MSFT,:USD}`.
The currency can be omitted and it will default to USD, e.g. `Stock(:MSFT)`.
"""
struct Stock{S,C} <: Instrument{S,C}
Stock(S::Symbol) = new{S,currency(:USD)}()
Stock(S::Symbol,CS::Symbol) = new{S,currency(CS)}()
Stock(S::Symbol,::Type{CS}) where {CS<:Currency} = new{S,CS}()
Stock(sym::Symbol, ccy::Symbol=:USD) = new{sym,currency(ccy)}()
Stock(sym::Symbol, ::Type{T}) where {T<:Currency} = new{sym,T}()
end

macro stock_str(str)
:( Stock(Symbol($(esc(str)))) )
"""
Return the singleton type for a particular general stock, given it's symbol.
Defaults to USD for the currency
"""
stock(sym::Symbol, ccy::Symbol=:USD) = Stock{sym,currency(ccy)}
stock(sym::Symbol, ::Type{T}) where {T<:Currency} = Stock{sym,T}

macro stock_str(str,ccy="USD")
:( stock(Symbol($(esc(str))),Symbol($(esc(ccy)))) )
end

# Set up short names for all of the currencies (as instances of the Cash instruments). This is really done as a convenience
# Set up short names for all of the currencies (as Cash instrument types).
# This is really done as a convenience
for (s,(ccy,u,c,n)) in Currencies.allpairs()
@eval const $s = Cash($ccy)
@eval const $s = cash($ccy)
end

end # module
end # module Assets
42 changes: 21 additions & 21 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Assets; using Assets: USD, EUR, JPY, JOD, CNY
using Currencies; using Currencies: currency, symbol, unit, code, name
using Instruments, FixedPointDecimals
using Assets, Currencies, Instruments, FixedPointDecimals

using Assets: USD, EUR, JPY, JOD, CNY
using Currencies: currency, symbol, unit, code, name

using Test

Expand All @@ -24,24 +25,23 @@ end
@testset "All currencies" begin
for sym in Currencies.allsymbols()
ccy = Currency{sym}()
cash = Base.eval(Assets, sym)
@test cash == Cash(ccy)
@test cash == Cash(symbol(ccy))
@test currency(cash) == typeof(ccy)
@test symbol(cash) == symbol(ccy)
@test unit(cash) == unit(ccy)
@test code(cash) == code(ccy)
@test name(cash) == name(ccy)
ct = Base.eval(Assets, sym)
@test ct == cash(ccy)
@test ct == cash(sym)
@test currency(ct) == typeof(ccy)
@test symbol(ct) == symbol(ccy)
@test unit(ct) == unit(ccy)
@test code(ct) == code(ccy)
@test name(ct) == name(ccy)

CT = typeof(cash)
position = Position{CT}(1)
@test currency(position) == currency(cash)
@test currency(1cash) == typeof(ccy)
@test 1cash == position
@test cash * 1 == position
@test 1cash + 1cash == Position{CT}(2)
@test 1cash - 1cash == Position{CT}(0)
@test 20cash / 4cash == FixedDecimal{Int,unit(cash)}(5)
@test 20cash / 4 == Position{CT}(5)
position = Position{ct}(1)
@test currency(position) == currency(ct)
@test currency(1ct) == typeof(ccy)
@test 1ct == position
@test ct * 1 == position
@test 1ct + 1ct == Position{ct}(2)
@test 1ct - 1ct == Position{ct}(0)
@test 20ct / 4ct == FixedDecimal{Int,unit(ct)}(5)
@test 20ct / 4 == Position{ct}(5)
end
end

0 comments on commit 6574b16

Please sign in to comment.