Skip to content

Commit

Permalink
added a lot of documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
louisponet committed Apr 15, 2023
1 parent 43226e3 commit 3be0c25
Show file tree
Hide file tree
Showing 12 changed files with 208 additions and 159 deletions.
5 changes: 3 additions & 2 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,9 @@ makedocs(; modules = [Trading],
"Topics" => ["Trader" => "trader.md",
"Brokers" => "brokers.md",
"Portfolio" => "portfolio.md",
"Time" => "time.md"],
"Data" => "data.md",
"Time" => "time.md",
"Ticker Ledgers" => "ticker_ledgers.md",
"Indicators" => "indicators.md"],
"Strategies" => ["strategies.md",
"idea_generation.md",
"Slow Fast" => "strategies/slow_fast.md",
Expand Down
69 changes: 65 additions & 4 deletions docs/src/brokers.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,75 @@
```@meta
CurrentModule=Trading
```
An [`AbstractBroker`](@ref) signifies the interface between the local [`Trader`](@ref) and an external party that supplies data, and potentially executes orders and holds the user's portfolio.
The current brokers are:
- [`AlpacaBroker`](@ref): the main "real" broker
- [`MockBroker`](@ref): behaves similarly to a real broker but with random data
- [`HistoricalBroker`](@ref): wraps another broker to supply historical data when [`BackTesting`](@ref BackTester)

## Data
### [Historical](@ref historical_data)
A slew of historical data can be requested through a broker e.g
```@example
using Trading#hide
broker = AlpacaBroker(ENV["ALPACA_KEY_ID"], ENV["ALPACA_SECRET"])
bars(broker, "AAPL", DateTime("2023-04-05T00:00:00"), DateTime("2023-04-05T22:00:00"), timeframe=Minute(1))
```

There are so far three such functions:
- [`bars`](@ref): retrieve historical bar data
- [`trades`](@ref): retrieve historical data on trades
- [`quotes`](@ref): retrieve historical data on quotes

### Realtime
The [Broker](@ref Brokers) can be queried for the [`current_price`](@ref) of an asset, and `bar` data can be streamed in
by calling [`bar_stream`](@ref), either in realtime from a realtime broker (e.g. [`AlpacaBroker`](@ref)), or faked realtime when using a [`HistoricalBroker`](@ref).

For example, internally [`start_data`](@ref) essentially looks like:
```julia
bar_stream(trader.broker) do stream
for (ticker, q) in trader.ticker_ledgers
register!(stream, ticker)
end
while !trader.stop_data
bars = receive(stream)
# distribute bars to ticker ledgers
end
end
```
See [`register!`](@ref) and [`receive`](@ref) for further information.

## Orders
Orders can be submitted with [`submit_order`](@ref) and updates to them can be streamed in with [`order_stream`](@ref).
Similarly to [`start_data`](@ref), [`start_trading`](@ref) opens an order stream so order updates can be passed along to the
[`Order`](@ref) `Component`:
```julia
order_stream(trader.broker) do stream
while !trader.stop_trading
order = receive(stream)
# update Order component
end
end
```
In general, however, these functions should not be used and one should rely on the core systems of the [`Trader`](@ref) to submit and handle orders through [`Purchase`](@ref) and [`Sale`](@ref) `Components`.
See [Portfolio](@ref) for more info.

## References

```@docs
Trading.AbstractBroker
Trading.AlpacaBroker
Trading.HistoricalBroker
Trading.MockBroker
```

```@docs
Trading.current_price
bars
trades
quotes
current_price
Trading.BarStream
Trading.bar_stream
Trading.HTTP.receive(b::Trading.BarStream)
Trading.register!(b::Trading.BarStream, ticker)
Trading.submit_order
Trading.OrderStream
Trading.order_stream
```
100 changes: 0 additions & 100 deletions docs/src/data.md

This file was deleted.

67 changes: 67 additions & 0 deletions docs/src/indicators.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Indicators

```@meta
CurrentModule = Trading
```

The basic `Components` like [`Open`](@ref), [`Close`](@ref), [`High`](@ref), [`Low`](@ref), [`Volume`](@ref) and their [`Difference`](@ref) or [`RelativeDifference`](@ref) components can be used
to generate derived `Components` like:
- [`SMA{horizon, base_T}`](@ref SMA): simple moving average over a window/horizon
- [`EMA{horizon, base_T}`](@ref EMA): exponential moving average over a window/horizon
- [`MovingStdDev{horizon, base_T}`](@ref MovingStdDev): moving standard deviation over a window/horizon
- [`RSI{horizon, base_T}`](@ref RSI): moving relative strength index over a window/horizon
- [`Bollinger{horizon, base_T}`](@ref Bollinger): Up and Down Bollinger bands

These indicators can be requested by [`Strategy`](@ref) systems for example:
```julia
struct TestStrat <: System

Overseer.requested_components(::TestStrat) = (SMA{20, Close}, RSI{14, Open})
```
This leads that for any ticker that `TestStrat` should be used on will automatically generate these derived `Indicators` as the data flows in.
It is also used by [`new_entities`](@ref) to iterate over the new entities in a [`TickerLedger`](@ref) that hold the requested components for a given [`Strategy`](@ref).
[`reset!`](@ref) on the other hand clears all the data for the requested components of a strategy in a [`TickerLedger`](@ref).
This is useful for example to not use the data of the previous day when calculating moving averages etc.

```julia
function update(s::TestStrat, trader, ticker_ledgers)
curt = current_time(trader)
if is_market_open(curt)
for l in ticker_ledgers
# This clears the SMA{20, Close} and RSI{14, Open} Components from l
reset!(l, s)
end
end
for l in ticker_ledgers
for e in new_entities(l, s)
# do something with e

# e[SMA{20, Close}] accesses the SMA
# e[RSI{14, Open}] accesses the RSI
end
end
end
```
Each `e` in the above example will be seen **only once**. See the [Strategies](@ref) tutorial for more info.

## Reference
```@docs
Trading.SMA
Trading.MovingStdDev
Trading.EMA
Trading.RSI
Trading.Bollinger
Trading.Sharpe
Trading.new_entities
Trading.reset!(::Trading.TickerLedger, ::Any)
```
## [Systems](@id indicator_systems)
```@docs
Trading.SMACalculator
Trading.MovingStdDevCalculator
Trading.EMACalculator
Trading.RSICalculator
Trading.BollingerCalculator
Trading.SharpeCalculator
```

2 changes: 1 addition & 1 deletion docs/src/strategies.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ See [`Slow Fast Strategy`](@ref slow_fast_id) for a full runnable version of thi

## References
```@docs
Trading.relative
Trading.Strategy
Trading.new_entities
NewEntitiesIterator
```
29 changes: 10 additions & 19 deletions docs/src/strategies/cointegration.jl
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ function Overseer.update(s::PairStrat, m::Trading.Trader, ticker_ledgers)
if new_pos || prev_e z_comp
continue
end

going_up = z_score - z_comp[prev_e].v > 0
if z_score > 0 && in_bought_leg && !going_up
Entity(m, Sale(ticker1, curpos1))
Expand Down Expand Up @@ -158,10 +159,12 @@ broker.fixed_transaction_fee = 0.0;
# Next we specify the daily cointegration parameters that were fit to 2022 data, and run the backtest on Minute data from the first 3 months of 2023.
γ = (0.83971041721211, 0.7802162996942561, 0.8150936011572303, 0.8665354500999517, 0.8253480013737815)

stratsys = [SpreadCalculator(γ), PairStrat{20}(γ, 2.5)]
stratsys = [SpreadCalculator(γ), PairStrat{20}(γ, 2.5)]
sim_start =TimeDate("2023-01-01T00:00:00")
sim_stop = TimeDate("2023-03-31T23:59:59")
trader = BackTester(broker; strategies=[Strategy(:pair, stratsys, tickers=["MSFT", "AAPL"])],
start=TimeDate("2023-03-01T00:00:00"),
stop=TimeDate("2023-03-31T23:59:59"))
start=sim_start,
stop=sim_stop)

start(trader)

Expand Down Expand Up @@ -261,24 +264,12 @@ reset!(trader)
start(trader)

ta = Trading.relative(only_trading(TimeArray(trader)))
to_plot = merge(ta[:portfolio_value], Trading.relative(rename(bars(broker, "MSFT", sim_start, sim_stop, timeframe=Minute(1))[:c], :MSFT_Close)),
Trading.relative(rename(bars(broker, "AAPL", sim_start, sim_stop, timeframe=Minute(1))[:c], :AAPL_Close)))

plot([ta[:MSFT_Close] ta[:AAPL_Close] ta[:portfolio_value]])

# Behold, a seemingly succesful strategy. We can even apply some penalties using the fees simulation
# available by setting some fields in the [`HistoricalBroker`](@ref). We will put a transaction fee per share of 0.5 cent.

trader.broker.variable_transaction_fee = 0.0
trader.broker.fee_per_share = 0.005
trader.broker.fixed_transaction_fee = 0.0

reset!(trader)
start(trader)

ta = Trading.relative(only_trading(TimeArray(trader)))

plot([ta[:MSFT_Close] ta[:AAPL_Close] ta[:portfolio_value]])
plot(to_plot)

# Not bad!
# Behold, a seemingly succesful strategy.

# ## Performance analysis

Expand Down
39 changes: 13 additions & 26 deletions docs/src/strategies/cointegration.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ function Overseer.update(s::PairStrat, m::Trading.Trader, ticker_ledgers)
if new_pos || prev_e ∉ z_comp
continue
end
going_up = z_score - z_comp[prev_e].v > 0
if z_score > 0 && in_bought_leg && !going_up
Entity(m, Sale(ticker1, curpos1))
Expand Down Expand Up @@ -176,9 +177,11 @@ Next we specify the daily cointegration parameters that were fit to 2022 data, a
γ = (0.83971041721211, 0.7802162996942561, 0.8150936011572303, 0.8665354500999517, 0.8253480013737815)
stratsys = [SpreadCalculator(γ), PairStrat{20}(γ, 2.5)]
sim_start =TimeDate("2023-01-01T00:00:00")
sim_stop = TimeDate("2023-03-31T23:59:59")
trader = BackTester(broker; strategies=[Strategy(:pair, stratsys, tickers=["MSFT", "AAPL"])],
start=TimeDate("2023-03-01T00:00:00"),
stop=TimeDate("2023-03-31T23:59:59"))
start=sim_start,
stop=sim_stop)
start(trader)
````
Expand Down Expand Up @@ -279,40 +282,24 @@ function Overseer.update(s::PairStrat, m::Trading.Trader, ticker_ledgers)
end
````

We reset the trader, and check our results:

````@example cointegration
reset!(trader)
start(trader)
ta = only_trading(TimeArray(trader))
plot([ta[:MSFT_Close] ta[:AAPL_Close] ta[:portfolio_value]])
````

Behold, a seemingly succesful strategy. We can even apply some penalties using the fees simulation
available by setting some fields in the [`HistoricalBroker`](@ref). We will put a transaction fee per share of 0.5 cent.
We reset the trader, and check our results (see [`Trading.relative`](@ref)):

````@example cointegration
trader.broker.variable_transaction_fee = 0.0
trader.broker.fee_per_share = 0.005
trader.broker.fixed_transaction_fee = 0.0
reset!(trader)
start(trader)
ta = only_trading(TimeArray(trader))
ta = Trading.relative(only_trading(TimeArray(trader)))
to_plot = merge(ta[:portfolio_value], Trading.relative(rename(bars(broker, "MSFT", sim_start, sim_stop, timeframe=Minute(1))[:c], :MSFT_Close)),
Trading.relative(rename(bars(broker, "AAPL", sim_start, sim_stop, timeframe=Minute(1))[:c], :AAPL_Close)))
plot([ta[:MSFT_Close] ta[:AAPL_Close] ta[:portfolio_value]])
plot(to_plot)
````

Not bad!
Behold, a seemingly succesful strategy.

````@example cointegration
# Performance analysis
````
## Performance analysis

See [Performance Analysis]
See [Performance Analysis](@ref)

````@example cointegration
using Trading.Analysis
Expand Down
Loading

0 comments on commit 3be0c25

Please sign in to comment.