Overall Statistics
Total Trades
1075
Average Win
0.40%
Average Loss
-0.29%
Compounding Annual Return
78.649%
Drawdown
11.400%
Expectancy
0.411
Net Profit
90.682%
Sharpe Ratio
2.996
Probabilistic Sharpe Ratio
97.138%
Loss Rate
41%
Win Rate
59%
Profit-Loss Ratio
1.39
Alpha
0.523
Beta
0.102
Annual Standard Deviation
0.172
Annual Variance
0.03
Information Ratio
2.362
Tracking Error
0.245
Treynor Ratio
5.053
Total Fees
$1231.14
Estimated Strategy Capacity
$23000000.00
Lowest Capacity Asset
MTD R735QTJ8XC9X
#region imports
from AlgorithmImports import *
#endregion
from io import StringIO
import pandas as pd
import math
import datetime
import random


class CalculatingFluorescentOrangeAlligator(QCAlgorithm):
    
    def Initialize(self):
        self.SetStartDate(2022, 1, 1)  # Set Start Date
        self.SetCash(100000)  # Set Strategy Cash
        self.AddEquity("SPY", Resolution.Daily)

        self.MAX_HOLDINGS = 20
        self.PROFIT_LIMIT = 60
        self.LOSS_LIMIT = 25
        self.LEVERAGE = 0.85
        
        rnd = random.randint(1, 999999999)
        # sym_csv = self.Download(f"https://storage.googleapis.com/forex-wolf/dataiku/STOCKDATAPREP2/top_traded_gcp/out-s0.csv?rnd={rnd}")
        # self.sym_df = pd.read_csv(StringIO(sym_csv), sep='\t')

        csv = self.Download(f"https://storage.googleapis.com/forex-wolf/dataiku/STOCKDATAPREP2/top10_gcp/out-s0.csv?rnd={rnd}")
        self.trade_df = pd.read_csv(StringIO(csv), sep='\t')

        for sym in self.trade_df['symbol'].unique():
            self.AddEquity(sym, Resolution.Daily)
        
        for key in self.ObjectStore.Keys:
            self.ObjectStore.Delete(key)

        self.last_day = ''
        
        self.Schedule.On(self.DateRules.EveryDay('SPY'), self.TimeRules.BeforeMarketClose('SPY', 20), self.BeforeMarketClose)

        self.ShortableProvider = AtreyuShortableProvider(SecurityType.Equity, Market.USA)

    def do_the_magic(self):
        tm = self.Time
        tm_str = tm.strftime("%Y-%m-%d")
        # self.Log(tm_str)

        if self.last_day != tm_str:
            self.last_day = tm_str

            date_field = 'generated_date'
            trades = self.trade_df.query(f'{date_field}=="{tm_str}"')

            running_pos = self.Portfolio.Cash
            for idx, row in trades.sort_values('proba', ascending=False).iterrows():
                sym = row["symbol"]
        
                if self.Securities[sym].HasData:
                    # val = data[sym]
                    price = self.Securities[sym].AskPrice
                    # price = val.Price

                    qty = math.floor(((self.Portfolio.TotalPortfolioValue * self.LEVERAGE) / self.MAX_HOLDINGS) / price)
                    qty = int(qty * row['prediction']) # 
                    
                    security_holding = self.Portfolio[sym]

                    # if not security_holding.Invested:
                    # self.Log(f'bought {qty} of {sym}')
                    # self.SetHoldings(sym, 1)
                    if qty != 0 and running_pos > 0:
                        self.MarketOnOpenOrder(sym, qty)
                    
                        key = sym + '-' + tm.strftime("%Y%m%d")
                        # self.Log(key)
                        self.ObjectStore.Save(key, str(qty) + "|" + str(price))

                        running_pos -= (qty * price)
                
            keys_to_remove = []
            for key in self.ObjectStore.Keys:
                qty, price = self.ObjectStore.Read(key).split('|')
                sym, dt_str = key.split('-')
                dt = datetime.datetime.strptime(dt_str, "%Y%m%d")

                price = float(price)

                cur_price = self.Securities[sym].AskPrice
                if ((dt + datetime.timedelta(days=14)) < tm or
                 (cur_price > (price * (1+self.PROFIT_LIMIT)) 
                 or cur_price < (price*(1-self.LOSS_LIMIT)))) and self.Portfolio[sym].HoldStock:
                    liq_qty = 0-int(qty)
                    self.MarketOnOpenOrder(sym, liq_qty)
                    # self.Log(f'Closing {sym} {liq_qty}')
                    keys_to_remove.append(key)

            for key in keys_to_remove:
                ok = self.ObjectStore.Delete(key)

    def BeforeMarketClose(self):
        self.do_the_magic()

    def BeforeMarketOpen(self):
        self.do_the_magic()