I want to create a backtesting python program, where I compare two EMA crossing as buy, sell signal against buy-and-hold lump sum investing.
The program will use yfinance to obtain market data and use Matplotlib to indicate where the strategy buy and sell. The historical price should be plot with candle style.’

It should calculate the total return, the sharp ratio, win rate, and max drawdown. Max drawdown define as the drawdown below the long entry price, i.e. if enter a trade at 100 and sell at 200, but during that period the price gone to 80, the drawdown should be -20%. and the max drawdown should be the biggest drawdown among all trade.

The EMA should change as the interval change, so if user input 12, 26 EMA. Under weekly candle, the strategy will be to buy when short 12 weeks EMA cross 26 weeks EMA, and sell when 12 weeks EMA fall below 26 weeks EMA. For daily candle it will be 12 days EMA and 26 days EMA, so on and so forth.

There should be a front end where user can enter what ticket they are backtesting for, what EMA numbers, what kind of candle(x hr, day, week, month), and what period to backtest. the EMA input should adapt to the selected candle interval. Use Streamlit as frontend. a log section under the chart section that display each buy and sell trade is also needed.


Here is a tradingview script as example for the EMA logic, expect we only have two EMA here.

//@version=4
study("EMA Cross", overlay=true)
// Einfacher EMA-Cross Indikator mit Indikation der Crosses auf EMA-Linie und am Chart-Bottom
//
// durtig aber wahr!

// Userinput: EMA-Längen und Quelle
ema_01_len = input(7, title='Ema 1', step=1, type=input.integer)
ema_02_len = input(21, title='Ema 2', step=1, type=input.integer)
ema_03_len = input(50, title='Ema 3', step=1, type=input.integer)
ema_04_len = input(200, title='Ema 4', step=1, type=input.integer)
ema_src = input(title="Source", type=input.source, defval=close)

// EMA-Werte berechnen lassen
ema_01 = ema(ema_src, ema_01_len)
ema_02 = ema(ema_src, ema_02_len)
ema_03 = ema(ema_src, ema_03_len)
ema_04 = ema(ema_src, ema_04_len)

//EMAs in Chart zeichen
plot(ema_01, title='ema_01', color=#00FF00, style=plot.style_line, linewidth=1)
plot(ema_02, title='ema_02', color=#ff0040, style=plot.style_line, linewidth=1)

plot(ema_03, title='ema_03', color=#0000FF, style=plot.style_line, linewidth=1)
plot(ema_04, title='ema_04', color=#ff2080, style=plot.style_line, linewidth=1)

//Cross detect
cross_01_up = crossover(ema_01, ema_02)
cross_01_down = crossunder(ema_01, ema_02)
//Wenn cross dann cross auf ema-level zeichnen
plot(cross_01_up or cross_01_down ? ema_01 : na, style=plot.style_cross, title="cross 01", linewidth=3, color=ema_01 > ema_02 ? color.green : color.red)
//Wenn cross, cross mit Text unten auf chart zeichnen
plotchar(cross_01_up or cross_01_down ? ema_01 : na, title="cross_01", char="x", location=location.bottom, color=ema_01 > ema_02 ? color.green : color.red, text="Cross 01", textcolor=ema_01 > ema_02 ? color.green : color.red)
//Cross2 detect
cross_02_up = crossover(ema_03, ema_04)
cross_02_down = crossunder(ema_03, ema_04)
//Wenn cross dann cross auf ema-level zeichnen
plot(cross_02_up or cross_02_down ? ema_03 : na, style=plot.style_cross, title="cross 02", linewidth=3, color=ema_03 > ema_04 ? color.green : color.red)
//Wenn cross, cross mit Text unten auf chart zeichnen
plotchar(cross_02_up or cross_02_down ? ema_03 : na, title="cross_02", char="x", location=location.bottom, color=ema_03 > ema_04 ? color.green : color.red, text="Cross 02", textcolor=ema_03 > ema_04 ? color.green : color.red)

alertcondition(cross_01_up, title='cross_01_up', message='a simple script is not a reason to buy! ;)')
alertcondition(cross_01_down, title='cross_01_down', message='a simple script is not a reason to sell! ;)')



Can you help me create the program