Overall Statistics
Total Trades
0
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Net Profit
0%
Sharpe Ratio
0
Probabilistic Sharpe Ratio
0%
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0
Beta
0
Annual Standard Deviation
0
Annual Variance
0
Information Ratio
0
Tracking Error
0
Treynor Ratio
0
Total Fees
$0.00
Estimated Strategy Capacity
$0
Lowest Capacity Asset
#region imports
from AlgorithmImports import *
#endregion


# Your New Python File
#region imports
from AlgorithmImports import *
#endregion

# Totally degenerate strategy which uses moving averages to trade momentum

class MaMomentumAlphaModel(AlphaModel):
    def __init__(self,
                resolution = Resolution.Daily):
        self.resolution = resolution;
        self.symbolDataBySymbol = {}
        
        self.allowed_tickers = ["BTCUSD"]

    def Update(self, algorithm: QCAlgorithm, data: Slice) -> List[Insight]:
        insights = []

        for symbol, symbolData in self.symbolDataBySymbol.items():
            if symbol.Value in self.allowed_tickers and symbolData.CheckReady():
                long_signal_count = 0;
                for selected_sma in symbolData.SmaList:
                    if data[symbol] > selected_sma:
                        long_signal_count += 1;

                if long_signal_count > 0:
                    insights.append(Insight.Price(symbolData.Symbol, timedelta(days=1), InsightDirection.Up, confidence=long_signal_count))

        return insights;

    def OnSecuritiesChanged(self, algorithm: QCAlgorithm, changes: SecurityChanges) -> None:
        for added in changes.AddedSecurities:
            symbolData = self.symbolDataBySymbol.get(added.Symbol)
            if symbolData is None:
                symbolData = SymbolData(added, algorithm, self.resolution)
                self.symbolDataBySymbol[added.Symbol] = symbolData
            else:
                # a security that was already initialized was re-added, reset the indicators
                symbolData.ResetAll()

        for removed in changes.RemovedSecurities:
            data = self.symbolDataBySymbol.pop(removed.Symbol, None)
            if data is not None:
                # clean up our consolidators
                data.RemoveConsolidators()

class SymbolData:
    '''Contains data specific to a symbol required by this model'''
    def __init__(self, security, algorithm, resolution):
        self.Security = security
        self.Symbol = security.Symbol
        self.algorithm = algorithm

        self.SmaList = []
        self.AllConsolidators = []

        period_list = [1, 2, 4, 10, 20];

        for period in period_list:
            self.AllConsolidators.append(algorithm.ResolveConsolidator(security.Symbol, resolution))

        for selected_consolidator in self.AllConsolidators:
            algorithm.SubscriptionManager.AddConsolidator(security.Symbol, selected_consolidator)

        for period in period_list:
            self.SmaList.append(SimpleMovingAverage(security.Symbol, period))

        for selected_sma, selected_consolidator in zip(self.SmaList, self.AllConsolidators):
            algorithm.RegisterIndicator(security.Symbol, selected_sma, selected_consolidator);

        for selected_sma in self.SmaList:
            algorithm.WarmUpIndicator(security.Symbol, selected_sma, resolution);

        #self.LongSignalCount = 0;
        
    def RemoveConsolidators(self):
        for selected_consolidator in self.AllConsolidators:
            self.algorithm.SubscriptionManager.RemoveConsolidator(self.Security.Symbol, selected_consolidator)
    
    def ResetAll(self):
        for selected_sma in self.SmaList:
            selected_sma.Reset();

    def CheckReady(self):
        for selected_sma in self.SmaList:
            if not selected_sma.IsReady:
                return False;
        return True;
#region imports
from AlgorithmImports import *
import numpy as np
import pandas as pd
from datetime import timedelta
#endregion

# Buy and HODL for last 3 days of the month
class TurnOfMonthAlphaModel(AlphaModel):
    def __init__(self,
                resolution = Resolution.Daily):
        self.securities = []
        self.resolution = resolution;

        self.allowed_tickers = ["BTCUSD"]
        
        month_list = [];
        for year in ["2018", "2019", "2020","2021","2022","2023","2024"]:
            for i in range(12):
                if i >= 9:
                    month_list.append(f"{year}{i+1}")
                else:
                    month_list.append(f"{year}0{i+1}")
        df_eom = pd.DataFrame({'Date': month_list})
        df_eom['EndOfMonth'] = pd.to_datetime(df_eom['Date'], format="%Y%m") + pd.tseries.offsets.MonthEnd(0)
        
        self.date_store = df_eom.EndOfMonth.dt.date.tolist()
    
    def Update(self, algorithm: QCAlgorithm, data: Slice) -> List[Insight]:
        insights = []
        
        if algorithm.Time.date() + timedelta(days=3) in self.date_store:
            for security in self.securities:
                # security price could be zero until we get the first data point. e.g. this could happen
                # when adding both forex and equities, we will first get a forex data point
                if security.Price != 0 and security.Symbol.Value in self.allowed_tickers:
                    insights.append(Insight(security.Symbol, timedelta(days=3), InsightType.Price, InsightDirection.Up))

        elif algorithm.Time.date() + timedelta(days=2) in self.date_store:
            for security in self.securities:
                # security price could be zero until we get the first data point. e.g. this could happen
                # when adding both forex and equities, we will first get a forex data point
                if security.Price != 0 and security.Symbol.Value in self.allowed_tickers:
                    insights.append(Insight(security.Symbol, timedelta(days=2), InsightType.Price, InsightDirection.Up))

        elif algorithm.Time.date() + timedelta(days=1) in self.date_store:
            for security in self.securities:
                # security price could be zero until we get the first data point. e.g. this could happen
                # when adding both forex and equities, we will first get a forex data point
                if security.Price != 0 and security.Symbol.Value in self.allowed_tickers:
                    insights.append(Insight(security.Symbol, timedelta(days=1), InsightType.Price, InsightDirection.Up))
        
        elif algorithm.Time.date() in self.date_store:
            for security in self.securities:
                # security price could be zero until we get the first data point. e.g. this could happen
                # when adding both forex and equities, we will first get a forex data point
                if security.Price != 0 and security.Symbol.Value in self.allowed_tickers:
                    insights.append(Insight(security.Symbol, timedelta(days=1), InsightType.Price, InsightDirection.Flat))

        return insights

    def OnSecuritiesChanged(self, algorithm: QCAlgorithm, changes: SecurityChanges) -> None:
        for added in changes.AddedSecurities:
                self.securities.append(added)

        for removed in changes.RemovedSecurities:
            if removed in self.securities:
                self.securities.remove(removed)

# region imports
from AlgorithmImports import *

from MeatLayers.TurnOfMonthAlphaModel import TurnOfMonthAlphaModel;
from MeatLayers.MaMomentumAlphaModel import MaMomentumAlphaModel;
# endregion

class MeatMonster(QCAlgorithmFramework):
    def Initialize(self):
        self.SetStartDate(2020, 1, 1)  # Set Start Date
        self.SetCash(100000)  # Set Strategy Cash

        tickers = ['BTCUSD', 'ETHUSD', 'ETCUSD', 'XMRUSD', 'ZECUSD', 'XRPUSD', 'LTCUSD']

        for i in range(len(tickers)):
            self.crypto = self.AddCrypto(tickers[i], Resolution.Daily, Market.Bitfinex)
            self.crypto.SetLeverage(1)
            self.crypto.SetFeeModel(CustomFeeModel())
            self.crypto = self.crypto.Symbol

        self.AddAlpha(MaMomentumAlphaModel())
        self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
        self.SetExecution(ImmediateExecutionModel())
        self.SetRiskManagement(NullRiskManagementModel())
    
class CustomFeeModel(FeeModel):
    def GetOrderFee(self, parameters):
        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.0003
        return OrderFee(CashAmount(fee, "USD"))