# Backtesting framework

**URL:** <https://discourse.julialang.org/t/backtesting-framework/47351>\
**Category:** Finance and Economics\
**Tags:** package, finance\
**Created:** [September 27, 2020, 7:36am UTC](https://discourse.julialang.org/t/backtesting-framework/47351 "2020-09-27T07:36:41Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![bicepjai](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bicepjai/32/18158_2.png) [@bicepjai](https://discourse.julialang.org/u/bicepjai)\
**Post date:** [September 27, 2020, 7:36am UTC](https://discourse.julialang.org/t/backtesting-framework/47351/1 "2020-09-27T07:36:42Z")

</div>

There seems to be no maintained package for trading backtesting framework like a framewokr in python called [backtrader](https://www.backtrader.com/docu/)  
I did come across

1. dysonance/Strategems.jl
2. JuliaQuant/TradingLogic.jl

Anyone in the process of creation or knows of a package that i have not come across ?

---

<div class="post-metadata">

**Author:** ![iblis17](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/iblis17/32/649_2.png) [@iblis17](https://discourse.julialang.org/u/iblis17)\
**Post date:** [December 30, 2020, 7:24am UTC](https://discourse.julialang.org/t/backtesting-framework/47351/2 "2020-12-30T07:24:28Z")

</div>

Well, we still lack backtesting framework. If you’re interested in rebooting the TradingLogic.jl, feel free to ping me in that repo, just show your blueprint.

---

<div class="post-metadata">

**Author:** ![bicepjai](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bicepjai/32/18158_2.png) [@bicepjai](https://discourse.julialang.org/u/bicepjai)\
**Post date:** [December 30, 2020, 8:53pm UTC](https://discourse.julialang.org/t/backtesting-framework/47351/3 "2020-12-30T20:53:51Z")

</div>

I will keep you posted. I am working on a design currently.

---

<div class="post-metadata">

**Author:** ![itchingpixels](https://avatars.discourse-cdn.com/v4/letter/i/eada6e/32.png) [@itchingpixels](https://discourse.julialang.org/u/itchingpixels)\
**Post date:** [March 22, 2021, 2:28pm UTC](https://discourse.julialang.org/t/backtesting-framework/47351/4 "2021-03-22T14:28:30Z")

</div>

hi @bicepjai !

I’m also working on a strictly vectorized single asset & portfolio backtesting framework as well.  
Ping me on Julia slack (Mark Aron Szulyovszky) or in DM here (or email or whatever Discourse allows you to do)!

---

<div class="post-metadata">

**Author:** ![W4C](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/w4c/32/43621_2.png) [@W4C](https://discourse.julialang.org/u/W4C)\
**Post date:** [July 7, 2023, 2:58pm UTC](https://discourse.julialang.org/t/backtesting-framework/47351/5 "2023-07-07T14:58:20Z")

</div>

Hi all,

[[ANN] Announcing Trading.jl](https://discourse.julialang.org/t/ann-announcing-trading-jl/97812/) may also be related.

[PingPong.jl](https://github.com/panifie/PingPong.jl) may also be considered.

Kind regards

---

<div class="post-metadata">

**Author:** ![tylerjthomas9](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tylerjthomas9/32/44878_2.png) [@tylerjthomas9](https://discourse.julialang.org/u/tylerjthomas9)\
**Post date:** [September 20, 2023, 3:47am UTC](https://discourse.julialang.org/t/backtesting-framework/47351/6 "2023-09-20T03:47:36Z")

</div>

[SaguaroTrader.jl](https://github.com/SaguaroCapital/SaguaroTrader.jl) is a schedule-driven backtesting engine in Julia. We developed it to satisfy our internal use cases, but we welcome any feedback for expanding the capabilities to fit more general use cases.

---

<div class="post-metadata">

**Author:** ![FemtoTrader](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/femtotrader/32/309_2.png) [@FemtoTrader](https://discourse.julialang.org/u/FemtoTrader)\
**Post date:** [December 20, 2023, 8:59am UTC](https://discourse.julialang.org/t/backtesting-framework/47351/7 "2023-12-20T08:59:51Z")

</div>

Hi @tylerjthomas9

Nice to see that qstrader have a Julia version (I used to be a contributor).  
I personally find the order\_sizer an approach which is a bit complex.  
Implementing function like order\_market\_target

> **[Market](https://docs.trality.com/trality-code-editor/api-documentation/order/creation/market#order_market_target)**

to simply manage orders as a certain target percent with respect to the portfolio value seems a bit simpler (but that’s probably a personal taste)

I wonder how do you manage technical analysis indicators.  
Which Julia lib are you using ?  
Did you see my post [Incremental Technical Analysis indicators](https://discourse.julialang.org/t/incremental-technical-analysis-indicators/107844) about implementing incremental technical analysis indicators ?

---

<div class="post-metadata">

**Author:** ![tylerjthomas9](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tylerjthomas9/32/44878_2.png) [@tylerjthomas9](https://discourse.julialang.org/u/tylerjthomas9)\
**Post date:** [December 20, 2023, 4:31pm UTC](https://discourse.julialang.org/t/backtesting-framework/47351/8 "2023-12-20T16:31:16Z")

</div>

It is great to hear from you. I had noticed that you were an active member of the Julia community. Thank you for the suggestion around the `order_sizer`.

> [@FemtoTrader](#):
>
> I wonder how do you manage technical analysis indicators.  
> Which Julia lib are you using ?

We do not currently do anything with technical analysis indicators. Our internal use case is simply to take a schedule of company weights and build portfolios around that schedule. However, we want to expand the libraries functionality to be more generally useful. I had not seen your post until now, but I will take a look at it.

---

<div class="post-metadata">

**Author:** ![FemtoTrader](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/femtotrader/32/309_2.png) [@FemtoTrader](https://discourse.julialang.org/u/FemtoTrader)\
**Post date:** [April 28, 2024, 3:54pm UTC](https://discourse.julialang.org/t/backtesting-framework/47351/9 "2024-04-28T15:54:03Z")

</div>

Some others Julia backtesters to be added to the list.

- Lucky [GitHub - oliviermilla/Lucky.jl: Lucky](https://github.com/oliviermilla/Lucky.jl)

- Bruno [GitHub - USU-Analytics-Solution-Center/Bruno.jl: Repository for the Julia package with financial tools for data generation, asset pricing and strategy testing](https://github.com/USU-Analytics-Solution-Center/Bruno.jl/)

- Fastback [Fastback.jl - Blazingly fast Julia backtester 🚀 | Fastback.jl](https://rbeeli.github.io/Fastback.jl)

PS : be also aware of my new package for porfolio analytics via online algorithm [Incremental portfolio analytics (OnlinePortfolioAnalytics.jl)](https://discourse.julialang.org/t/incremental-portfolio-analytics-onlineportfolioanalytics-jl/113590)

---

<div class="post-metadata">

**Author:** ![FemtoTrader](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/femtotrader/32/309_2.png) [@FemtoTrader](https://discourse.julialang.org/u/FemtoTrader)\
**Post date:** [November 8, 2024, 1:36pm UTC](https://discourse.julialang.org/t/backtesting-framework/47351/10 "2024-11-08T13:36:28Z")

</div>

We are having one less Julia backtesting framework… [https://github.com/panifie/PingPong.jl](https://github.com/panifie/PingPong.jl)  
My 7 months late fork is available at [GitHub - femtotrader/PingPong.jl: Cryptocurrency trading bot, and backtesting framework in julia](https://github.com/femtotrader/PingPong.jl)  
[PingPong · Julia Packages](https://juliapackages.com/p/pingpong)

---

<div class="post-metadata">

**Author:** ![g-gundam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/g-gundam/32/47593_2.png) [@g-gundam](https://discourse.julialang.org/u/g-gundam)\
**Post date:** [November 14, 2024, 6:49pm UTC](https://discourse.julialang.org/t/backtesting-framework/47351/11 "2024-11-14T18:49:55Z")

</div>

What changes did you make to your fork of PingPong.jl?

---

<div class="post-metadata">

**Author:** ![FemtoTrader](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/femtotrader/32/309_2.png) [@FemtoTrader](https://discourse.julialang.org/u/FemtoTrader)\
**Post date:** [November 14, 2024, 7:35pm UTC](https://discourse.julialang.org/t/backtesting-framework/47351/12 "2024-11-14T19:35:52Z")

</div>

None. Sometimes I fork on GH because I consider that a project is interesting and I’d prefer to still have this code if it disappears.

---

<div class="post-metadata">

**Author:** ![g-gundam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/g-gundam/32/47593_2.png) [@g-gundam](https://discourse.julialang.org/u/g-gundam)\
**Post date:** [November 24, 2024, 5:25am UTC](https://discourse.julialang.org/t/backtesting-framework/47351/13 "2024-11-24T05:25:57Z")

</div>

Lucky.jl has a really interesting architecture. I just wish it were easier to use it with OnlineTechnicalIndicators.jl. I see that you even started an [issue](https://github.com/oliviermilla/Lucky.jl/issues/14) asking him about it.

I’ve been thinking about this problem space for a while, and the way he used Rocket.jl to organize his data pipeline feels elegant. He did a lot of things right. Even if I don’t end up using Lucky.jl for my own work, I think I will take a lot of inspiration from it.

---

<div class="post-metadata">

**Author:** ![oliviermilla](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oliviermilla/32/47200_2.png) [@oliviermilla](https://discourse.julialang.org/u/oliviermilla)\
**Post date:** [December 21, 2024, 10:19am UTC](https://discourse.julialang.org/t/backtesting-framework/47351/14 "2024-12-21T10:19:34Z")

</div>

Hello @g-gundam, OnlineTechnicalIndicators.jl is a great library and I’ve had multiple talks with @FemtoTrader about making one work with the other.

Current Lucky.jl design does not match the way indicators are built in OnlineTechnicalIndicators.jl. I could look again in the future, but I invite you to build a custom operator in Lucky.jl using OnlineTechnicalIndicators.jl. You might find the right way to make both work together.

I’ll gladly answer to any question here or on Github discussions.

---

<div class="post-metadata">

**Author:** ![g-gundam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/g-gundam/32/47593_2.png) [@g-gundam](https://discourse.julialang.org/u/g-gundam)\
**Post date:** [December 22, 2024, 1:34am UTC](https://discourse.julialang.org/t/backtesting-framework/47351/15 "2024-12-22T01:34:59Z")

</div>

I’ve been looking at your [`examples/goldencross.jl`](https://github.com/oliviermilla/Lucky.jl/blob/main/examples/goldencross.jl), and I know a bit more about Rocket.jl than I did a month ago. I see how I can get OHLC values from [`source`](https://github.com/oliviermilla/Lucky.jl/blob/main/examples/goldencross.jl#L55). That’s all I need to start calculating indicator values using OnlineTechnicalIndicators.jl. **However** , it won’t use the Lucky.jl indicator system (which I don’t understand yet), but it will co-exist alongside it. I think that’s better than nothing, and it’s a start.

It’s not going to be an operator either. I’m going to add another subject to do this. I don’t know if this is the right or wrong way to use Rocket.jl, but it is what’s worked for me so far. You were curious about how I was doing things with Rocket.jl in the other thread, and now you will see.

- [goldencross.jl with OnlineTechnicalIndicators](https://gist.github.com/g-gundam/e27f4a319fafb7369ac2fbf1675d8e74)

```julia
# I visualized the SMAs your strategy was using,
# so you can see where you're going.
chart_subject = ChartSubject(charts = Dict(
    :daily => Chart(
        "AAPL", Day(1),
        indicators = [
            SMA{Float64}(period=5),
            SMA{Float64}(period=2),
        ],
        visuals = [
            # The periods were so small, 
            # so it didn't look good without LWC_CURVED.
            Dict(
                :line_color => "#f4b860",
                :line_width => 4,
                :line_type => LWC_CURVED
            ),
            Dict(
                :line_color => "#537ce2",
                :line_width => 2,
                :line_type => LWC_CURVED
            ),
        ]
    )
))
subscribe!(source, chart_subject)

```

PS: I feel like your strategy should be executing more trades than it does.

---

<div class="post-metadata">

**Author:** ![oliviermilla](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oliviermilla/32/47200_2.png) [@oliviermilla](https://discourse.julialang.org/u/oliviermilla)\
**Post date:** [December 23, 2024, 2:05pm UTC](https://discourse.julialang.org/t/backtesting-framework/47351/16 "2024-12-23T14:05:58Z")

</div>

Absolutely, it’s better to have something than nothing. A few random comments quickly reading your code, for the conversation and mutual feedback!

If you want to try OnlineTechnicalIndicators with Lucky,

- Add an extension for OnlineTechnicalIndicators  
There:
- Define a type (A) for the Indicator you wish to port. See [Lucky.jl/src/indicators at main · oliviermilla/Lucky.jl](https://github.com/oliviermilla/Lucky.jl/tree/main/src/indicators) for examples.
- Write an Operator that takes whatever input and outputs A. The code inside should simply call OnlineTechnicalIndicators. See [Lucky.jl/src/operators/sma.jl at main · oliviermilla/Lucky.jl](https://github.com/oliviermilla/Lucky.jl/blob/main/src/operators/sma.jl) for instance that use Statistics (where you could use OnlineTechnicalIndicators instead).

All of the above is about 5 lines to create the Indicator and 15 to have the operator. Should be fast to try if it works! It would be nice though if the operator stuck to the current library conventions : 1/it works on streaming data 2/uses `Missing` for holes in the output data.

- I see you hardcoded some types such as `EMA{Float64}(period=45)`  
Indicators in Lucky have an interface to make it cleaner for anyone to get such types: The interface function is `IndicatorType`.

- The Lucky IndicatorType was made to be fully dispatchable. Are `SMA{Float64}(period=5)`also dispatchable at the period level ? Nothing bad here, simply a design choice versus another.

- I’m not sure what should subscribe to ChartSubject. It seems like some kind of Blotter to render charts. In which case, I believe integrating with Genie.jl to be the way as both framework are reactive and should work great together out of the box.

-not sure i understand that comment: ` yield() # INFO: This allows ExchangeFillSubject to have a chance to work.`

- If you indeed need multiple subscribers to ChartSubject, the way is probably to have a single subscriber in your code, and then use the multicast/share/publish operator to have multiple subscribers. (Just for information: Same goes if you want to have multiple input as a single subscription: you can use one of the combineLatest operator from Rocket.jl).

I’ve not had the chance to run your code though, I hope to do soon, at least to look at the nice charts. 🙂

Have a great day.

---

<div class="post-metadata">

**Author:** ![g-gundam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/g-gundam/32/47593_2.png) [@g-gundam](https://discourse.julialang.org/u/g-gundam)\
**Post date:** [December 23, 2024, 8:54pm UTC](https://discourse.julialang.org/t/backtesting-framework/47351/17 "2024-12-23T20:54:27Z")

</div>

> If you want to try OnlineTechnicalIndicators with Lucky, (… explanation omitted …)

Thanks for explaining how you might go about incorporating OnlineTechnicalIndicators into the Lucky indicator system. If I have some down time later, I may explore this. The thing that may slow me down the most at this point is my lack of understanding when it comes to Rocket.jl operators. I have yet to make one or even use one.

> Are SMA{Float64}(period=5) also dispatchable at the period level?

I don’t think the period of an indicator is something you can dispatch on with OnlineTechnicalIndicators.jl. (@femtotrader - please correct me if I’m wrong.)

```julia-repl
julia> using OnlineTechnicalIndicators

julia> sma50 = SMA{Float64}(period=50)
SMA: n=0 | value=missing

julia> sma200 = SMA{Float64}(period=200)
SMA: n=0 | value=missing

julia> typeof(sma50) == typeof(sma200) # They're the same type.
true

```

Personally, I’m fine with that.

> I’m not sure what should subscribe to ChartSubject. It seems like some kind of Blotter to render charts.

The ChartSubject is a thin wrapper around the Chart struct from my library, TechnicalIndicatorCharts.jl. It’s designed to consume candles and incrementally build a DataFrame that contains OHLCV values + indicator values calculated by OnlineTechnicalIndicators.jl. In my own trading system, I have a StrategySubject that subscribes to the ChartSubject, and it uses the data inside the `chart_subject` instance to make trading decisions.

Whereas you have an `on_next!` for each indicator:

```julia
Rocket.on_next!(strat::GoldenCross, data::SlowIndicatorType)
Rocket.on_next!(strat::GoldenCross, data::FastIndicatorType)

```

I have one comparable `on_next!` that looks like:

```julia
Rocket.on_next!(subject::StrategySubject, t::Tuple{Symbol, Candle})

```

That fires when ChartSubject has formed a complete candle for a Chart. Every complete candle implies all indicators in a Chart had new values calculated for them, so the ChartSubject notifies the StrategySubject with that tuple. Then, the StrategySubject uses the chart data that it already has access to to make trading decisions.

I really don’t want to confuse you further, but if you’re really curious, you can take a peek over at my very experimental code in [g-gundam/TradingPipeline.jl](https://github.com/g-gundam/TradingPipeline.jl).

> not sure i understand that comment: `yield() # INFO: This allows ExchangeFillSubject to have a chance to work.`

I have my own simulation pipeline, and it uses Channels to report back that an order was filled or if a stop loss was hit. The problem was that the Rocket loop was so tight that an order was put in and filled, but the fill response didn’t get reported back until months later in simulated time. The async task that I had monitoring the Channel didn’t get a chance to work until I put that yield there. Then the order fill responses came back in a timely manner.

In realtime situations, the yield wouldn’t have been needed, but in simulation, I needed it. Rocket was too fast.

> multicast

Thanks for the tip. I still have a lot to learn about Rocket.

---

<div class="post-metadata">

**Author:** ![g-gundam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/g-gundam/32/47593_2.png) [@g-gundam](https://discourse.julialang.org/u/g-gundam)\
**Post date:** [December 23, 2024, 9:10pm UTC](https://discourse.julialang.org/t/backtesting-framework/47351/18 "2024-12-23T21:10:35Z")

</div>

StrategySubject is driven by a state machine that looks like this:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/3/5/35ed6a87f759d0f48e1907051b3fbf8cd9825c79.png)

More complex strategies may require more complex state machines, but this is what I’m starting with.

---

<div class="post-metadata">

**Author:** ![oliviermilla](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oliviermilla/32/47200_2.png) [@oliviermilla](https://discourse.julialang.org/u/oliviermilla)\
**Post date:** [December 23, 2024, 9:58pm UTC](https://discourse.julialang.org/t/backtesting-framework/47351/19 "2024-12-23T21:58:51Z")

</div>

oh sh\*t, PingPong.jl is gone! What happened?!

---

<div class="post-metadata">

**Author:** ![g-gundam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/g-gundam/32/47593_2.png) [@g-gundam](https://discourse.julialang.org/u/g-gundam)\
**Post date:** [December 23, 2024, 10:03pm UTC](https://discourse.julialang.org/t/backtesting-framework/47351/20 "2024-12-23T22:03:56Z")

</div>

The user who created it is gone too.  
[https://github.com/panifie](https://github.com/panifie)

[Next page](https://discourse.julialang.org/t/backtesting-framework/47351.md?page=2)
