diff --git a/Project.toml b/Project.toml index 635db01..8524279 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "SaguaroTrader" uuid = "26277856-a3f7-4646-aaac-f090473ab108" authors = ["Tyler Thomas "] -version = "0.1.1" +version = "0.1.2" [deps] CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" diff --git a/src/data/daily_bar_csv.jl b/src/data/daily_bar_csv.jl index 39b12a1..d82059c 100644 --- a/src/data/daily_bar_csv.jl +++ b/src/data/daily_bar_csv.jl @@ -254,21 +254,21 @@ struct CSVDailyBarSource <: DataSource end end -function get_bid(ds::CSVDailyBarSource, dt::DateTime, asset::Symbol) +function get_bid(ds::CSVDailyBarSource, dt::DateTime, asset::Symbol)::Float64 df_bid_ask = ds.dict_asset_dfs[asset] - ix = searchsortedfirst(df_bid_ask.timestamp::Vector{DateTime}, dt)::Union{Nothing,Int64} - if isnothing(ix) || (ix == 1) - return float(NaN)::Float64 + ix = searchsortedfirst(df_bid_ask.timestamp::Vector{DateTime}, dt)::Int64 + if (ix == 1) || (ix > size(df_bid_ask, 1)) + return NaN else return @inbounds df_bid_ask[ix, :Bid]::Float64 end end -function get_ask(ds::CSVDailyBarSource, dt::DateTime, asset::Symbol) +function get_ask(ds::CSVDailyBarSource, dt::DateTime, asset::Symbol)::Float64 df_bid_ask = ds.dict_asset_dfs[asset] - ix = searchsortedfirst(df_bid_ask.timestamp::Vector{DateTime}, dt)::Union{Nothing,Int64} - if isnothing(ix) || (ix == 1) - return float(NaN)::Float64 + ix = searchsortedfirst(df_bid_ask.timestamp::Vector{DateTime}, dt)::Int64 + if (ix == 1) || (ix > size(df_bid_ask, 1)) + return NaN else return @inbounds df_bid_ask[ix, :Ask]::Float64 end diff --git a/src/precompile.jl b/src/precompile.jl index 710a276..ea1c547 100644 --- a/src/precompile.jl +++ b/src/precompile.jl @@ -6,42 +6,82 @@ using SnoopPrecompile portfolio_id = "test_port" start_dt = DateTime(2020, 1, 1) end_dt = DateTime(2020, 12, 31) + signal_weights = Dict(Equity(:AMD) => 1.0, Equity(:INTC) => 1.0) + rolling_signal_weights = Dict( + DateTime(2020) => Dict(Equity(:AMD) => 1.0, Equity(:INTC) => 1.0), + DateTime(2021) => Dict(Equity(:INTC) => 1.0), + DateTime(2022) => Dict(Equity(:AMD) => 1.0), + ) @precompile_all_calls begin # all calls in this block will be precompiled, regardless of whether # they belong to your package or not (on Julia 1.8 and higher) - # This was just taking from test/backtest.jl - # Better precompile should be done, but this significantly reduced latency - # Especially - - assets = [Equity(:AMD), Equity(:INTC), Equity(:NVDA)] - universe = StaticUniverse(assets) - # This brings the CSVDailyBarSource test from 5s to 0.3s on v1.9-rc1 - # ds = CSVDailyBarSource("./test/test_data") #TODO: should we just hardcode an example df? - # dh = BacktestDataHandler([ds]) - # port_optimizer = EqualWeightPortfolioOptimizer(dh) - # broker = SimulatedBroker( - # DateTime(2020), SimulatedExchange(DateTime(2020)), dh; initial_cash=100_000.0 - # ) - # create_portfolio!(broker, 75_000; portfolio_id=portfolio_id) - # order_sizer = DollarWeightedOrderSizer(0.01) - signal_weights = Dict(Equity(:AMD) => 1.0, Equity(:INTC) => 1.0) + ##################################################################### + # Universe + static_assets = [Equity(:AMD), Equity(:INTC), Equity(:NVDA), Cash()] + uni = StaticUniverse(static_assets) + + # dynamic universe + dynamic_assets = Dict( + Equity(:AMD) => start_dt, + Equity(:INTC) => start_dt, + Equity(:NVDA) => start_dt, + Cash() => start_dt, + ) + uni = DynamicUniverse(dynamic_assets) + _get_assets(uni, end_dt) + + ##################################################################### + # Order + ord1 = Order(start_dt, 100.0, Equity(:AMD)) + ord2 = Order(start_dt, 100.0, Equity(:AMD)) + equal_orders(ord1, ord2) + + ##################################################################### + # Rebalance + BuyAndHoldRebalance(Date(2022, 1, 1)) + WeeklyRebalance(Date(2022, 1, 1), Date(2022, 3, 1)) + MonthlyRebalance(Date(2022, 1, 1), Date(2022, 3, 1)) + + ##################################################################### + # Exchange + is_open(SimulatedExchange(start_dt), end_dt) + is_open(AlwaysOpenExchange(start_dt), end_dt) + + ##################################################################### + # Fee Model + calculate_fee(ZeroFeeModel(), 100.0, 10.0) + calculate_fee(PercentFeeModel(; tax_pct=0.15, fee_pct=0.10), 100.0, 10.0) + + ##################################################################### + # Data + + ##################################################################### + # Portfolio + create_subscription(DateTime(2022, 1, 1), 50.0, 100.0) + create_withdrawal(DateTime(2022, 1, 1), 50.0, 100.0) + create_asset_transaction(DateTime(2022, 1, 1), 50.0, 100.0, 1) # buy + create_asset_transaction(DateTime(2022, 1, 1), 50.0, 100.0, -1) # sell + + port = Portfolio(DateTime(2022, 1, 1), 100_000.0, "USD") + total_market_value(port) + total_equity(port) + total_unrealized_pnl(port) + total_realized_pnl(port) + total_pnl(port) + subscribe_funds!(port, DateTime(2022, 2, 1), 50_000.0) + withdraw_funds!(port, DateTime(2022, 2, 2), 50_000.0) + txn = Transaction(Equity(:AMD), 10.0, DateTime(2022, 2, 2), 50.0, 0.1) + transact_asset!(port, txn) + + ##################################################################### + # Alpha Model alpha_model = FixedSignalsAlphaModel(signal_weights) - # port_optimizer = FixedWeightPortfolioOptimizer(dh) - rebalance = DailyRebalance(Date(start_dt), Date(end_dt)) - - # trading_session = BacktestTradingSession( - # start_dt, - # end_dt, - # universe, - # broker, - # alpha_model, - # rebalance, - # portfolio_id, - # order_sizer, - # port_optimizer, - # ) - # run!(trading_session) + alpha_model(DateTime(2022, 1, 1)) + alpha_model = SingleSignalAlphaModel(StaticUniverse(static_assets), 1.0) + alpha_model(DateTime(2022, 1, 1)) + alpha_model = RollingSignalsAlphaModel(rolling_signal_weights) + alpha_model(DateTime(2022, 1, 1)) end end diff --git a/test/portfolio.jl b/test/portfolio.jl index 0c79169..e2be566 100644 --- a/test/portfolio.jl +++ b/test/portfolio.jl @@ -69,17 +69,6 @@ end @test pe.type == "sell_asset" end -@testset "PortfolioEvent" begin - pe = create_subscription(DateTime(2022, 1, 1), 50.0, 100.0) - @test pe.type == "subscription" - pe = create_withdrawal(DateTime(2022, 1, 1), 50.0, 100.0) - @test pe.type == "withdrawal" - pe = create_asset_transaction(DateTime(2022, 1, 1), 50.0, 100.0, 1) - @test pe.type == "buy_asset" - pe = create_asset_transaction(DateTime(2022, 1, 1), 50.0, 100.0, -1) - @test pe.type == "sell_asset" -end - @testset "Portfolio" begin port = Portfolio(DateTime(2022, 1, 1), 100_000.0, "USD") @test total_market_value(port) == 0.0