| Overall Statistics |
|
Total Orders 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Start Equity 10000 End Equity 10000 Net Profit 0% Sharpe Ratio 0 Sortino 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 Portfolio Turnover 0% Drawdown Recovery 0 |
# region imports
from AlgorithmImports import *
import math
import datetime
from statistics import fmean, pstdev
import copy
from enum import StrEnum, auto
# endregion
class Action(StrEnum):
BOUGHT_LONG = auto()
SOLD_SHORT = auto()
ADDED_TO_LONG = auto()
ADDED_TO_SHORT = auto()
CLOSED_LONG_POSITION = auto()
CLOSED_SHORT_POSITION = auto()
class Exit(StrEnum):
TAKE_PROFIT = auto()
STOP_LOSS = auto()
END_OF_DAY = auto()
class SP500Algorithm(QCAlgorithm):
def initialize(self):
self.initial_margin = 1600
self.maintenance_margin = 1100
self.initial_cash = 10000
self.portfolio_buffer = 0.15
self.margin_buffer = 0.05
self.order_fee = 0.60
self.set_start_date(2025, 1, 2)
self.set_end_date(2025, 1, 2)
self.set_cash(self.initial_cash)
self.set_brokerage_model(BrokerageName.INTERACTIVE_BROKERS_BROKERAGE, AccountType.MARGIN)
# Add S&P 500 E-mini futures contract
# Read https://www.quantconnect.com/docs/v2/writing-algorithms/universes/futures for more on parameters
self._continuous_contract = self.add_future(Futures.Indices.MICRO_SP_500_E_MINI,
resolution=Resolution.TICK,
data_normalization_mode=DataNormalizationMode.RAW,
data_mapping_mode=DataMappingMode.OpenInterest,
contract_depth_offset=0,
extended_market_hours=False)
self.sp500symbol = self._continuous_contract.symbol
self._sma20 = SimpleMovingAverage(20)
self._atr = AverageTrueRange(6, MovingAverageType.SIMPLE)
self.rate = InterestRateProvider()
self._sr = self.sr(self.sp500symbol, 22, self.rate.get_interest_rate(self.time), Resolution.DAILY)
self._sr_annual = self.sr(self.sp500symbol, 252, self.rate.get_interest_rate(self.time), Resolution.DAILY)
self._std = self.std(self.sp500symbol, 22, Resolution.DAILY)
self._std_annual = self.std(self.sp500symbol, 252, Resolution.DAILY)
self._current_contract = None
self.holding = None
# Get the time zone of the exchange for a specific asset.
time_zone = self.securities[self.sp500symbol].exchange.hours.time_zone
self.set_time_zone(time_zone)
self.exchange = self.securities[self.sp500symbol].exchange
self.schedule.on(
self.date_rules.every_day(self.sp500symbol),
self.time_rules.midnight,
self.update_market_time
)
# for daily summary report
self.schedule.on(
self.date_rules.every_day(self.sp500symbol),
self.time_rules.after_market_close(self.sp500symbol),
self.update_summary_report
)
# reset indicators/windows every midnight
self.schedule.on(
self.date_rules.every_day(self.sp500symbol),
self.time_rules.midnight,
self.reset_values
)
# for buy and sell signal
self.buy_atr = 0
self.sell_atr = 0
self.bar_counter = 0
self.increasing_high = None
self.decreasing_low = None
self.first_buy_condition = False
self.third_buy_condition = False
self.first_sell_condition = False
self.third_sell_condition = False
# record previous data
self._trade_bar_window = RollingWindow[TradeBar](3)
self._sma20_window = RollingWindow[float](2)
self._consolidator = TickConsolidator(timedelta(minutes=5))
self._consolidator.data_consolidated += self._consolidation_handler
self.subscription_manager.add_consolidator(self.sp500symbol, self._consolidator)
self.summary_list = []
self.action_type = None
self.exit_type = None
self.total_position = 0 # average fill price times quantity
self.margin_list = []
self.portfolio_cash_list = []
self.portfolio_value_list = []
self.trading_fees_list = []
self.sharpe_ratio_info = []
self.set_trade_builder(TradeBuilder(FillGroupingMethod.FLAT_TO_FLAT, FillMatchingMethod.FIFO))
self.log_header()
self.security_exchange_hours = self.securities[self.sp500symbol].exchange.hours
self.update_market_time()
def log_header(self):
# self.log(", Date, Time, Current SMA-20,SP 500 High,SP 500 Low,SP 500 Close,SP 500 Volume,ATR,Increasing High,Decreasing Low,Status")
# self.log(",Open,High,Low,Close,Volume")
pass
def calculate_contracts(self):
buffer = self.calculate_margin_buffer()
available_cash = self.portfolio.cash - buffer
contracts = math.floor((available_cash/(self.initial_margin + self.maintenance_margin))* 2/3)
if available_cash + (buffer * 0.10) >= contracts *(self.order_fee + self.initial_margin + self.maintenance_margin):
self.half_contracts = math.floor(contracts/2)
return contracts
else:
self.half_contracts = math.floor((contracts-1)/2)
return contracts - 1
def calculate_margin_buffer(self):
if self.portfolio_buffer * self.portfolio.cash > self.initial_margin * (1 + self.margin_buffer):
return self.portfolio_buffer * self.initial_cash
else:
return self.initial_margin * (1 + self.margin_buffer)
def csv_log(self, message):
bar = self._trade_bar_window[0]
# self.log(f",{self.time.date()}, {self.time.time()}, {self.current_sma20_value}, {bar.high}, {bar.low}, {bar.close}, {bar.volume}, {self._atr.current.value}, {self.increasing_high}, {self.decreasing_low}, {message}")
def update_market_time(self):
self.market_open = self.security_exchange_hours.get_next_market_open(self.time, extended_market_hours=False)
self.market_close = self.security_exchange_hours.get_next_market_close(self.time, extended_market_hours=False)
def update_summary_report(self):
# for summary report
self.portfolio_cash_list.append(f",{self.time.date()}, {self.time.time()}, Portfolio Cash, {self.portfolio.cash}")
self.portfolio_value_list.append(f",{self.time.date()}, {self.time.time()}, Portfolio Value, {self.portfolio.total_portfolio_value}")
self.trading_fees_list.append(f",{self.time.date()}, {self.time.time()}, Trading Fees, {self.portfolio.total_fees}")
self.sharpe_ratio_info.append(f",{self.time.date()}, {self.time.time()}, Risk Free Rate, {self.rate.get_interest_rate(self.time)}, Portfolio Value, {self.portfolio.total_portfolio_value}, Sharpe Ratio Monthly, {self._sr.current.value}, Standard Deviation Monthly, {self._std.current.value}, Sharpe Ratio Annual, {self._sr_annual.current.value}, Standard Deviation Annual, {self._std_annual.current.value}")
# self.generate_report()
def on_order_event(self, order_event: OrderEvent) -> None:
"Record order event for log file summary"
order = self.transactions.get_order_by_id(order_event.order_id)
if order_event.status == OrderStatus.FILLED:
if self.holding.invested:
pnl = ""
else:
pnl = -(order_event.fill_price * order_event.fill_quantity + self.total_position) * 5
s = f"{self.time.date()}, {self.time.time()}, {order_event.symbol}, {order_event.fill_price}, {order_event.fill_quantity}, {pnl}, {self.action_type}, {self.exit_type}, {self._atr.current.value:.3f}, {order_event.order_fee}, {self.portfolio.total_portfolio_value}"
self.summary_list.append(s)
# portfolio info log output for analysis
s = f"{self.time}, {self.portfolio.cash}, {self.portfolio.total_margin_used}, {self.portfolio.get_margin_remaining(self.sp500symbol, OrderDirection.BUY)}"
self.margin_list.append(s)
def _order_handler(self, tick):
"Handles tick data with 20 millisecond (backtesting) or 70 millisecond (live) period after getting a position."
bar = self._trade_bar_window[0]
previous_bar = self._trade_bar_window[1]
second_previous_bar = self._trade_bar_window[2]
self.current_sma20_value = self._sma20.current.value
current_time = self.time
closing_day = self.market_close - datetime.timedelta(minutes=61)
end_of_day = current_time >= closing_day
# 1st liquidate condition:take profit
# 2nd liquidate condition: stop loss
# 3rd liquidate condition: 3:59PM closing time
if self.holding.is_long:
take_profit_period = self.buy_atr * 2.5
take_profit = tick.price >= self.holding.average_price + take_profit_period
stop_loss_period = self.buy_atr * 1.5
take_profit_half_period = self.holding.average_price + take_profit_period/2
stop_loss = tick.price <= self.holding.average_price - stop_loss_period
if take_profit:
self.exit_type = Exit.TAKE_PROFIT
self.csv_log("trade entered: liquidating - taking profit")
s = f", {self.holding.average_price + take_profit_period},"
elif stop_loss:
self.exit_type = Exit.STOP_LOSS
self.csv_log("trade entered: liquidating - stop loss")
s = f", , {self.holding.average_price - stop_loss_period}"
elif end_of_day:
self.exit_type = Exit.END_OF_DAY
self.csv_log(f"trade entered: liquidating - closing date at {closing_day}")
s = ", , "
if take_profit or stop_loss or end_of_day:
self.action_type = Action.CLOSED_LONG_POSITION
self.liquidate(self._current_contract.symbol)
self.total_position = 0
self.summary_list[-1] += s
return
# 1st liquidate condition: take profit
# 2nd liquidate condition: stop loss
# 3rd liquidate condition: 3:59PM closing time
if self.holding.is_short:
take_profit_period = self.sell_atr * 2.5
take_profit = tick.price <= self.holding.average_price - take_profit_period
stop_loss_period = self.sell_atr * 1.5
take_profit_half_period = self.holding.average_price - take_profit_period/2
stop_loss = tick.price >= self.holding.average_price + stop_loss_period
if take_profit:
self.exit_type = Exit.TAKE_PROFIT
self.csv_log("trade entered: liquidating - taking profit")
s = f", {self.holding.average_price - take_profit_period}, "
elif stop_loss:
self.exit_type = Exit.STOP_LOSS
self.csv_log("trade entered: liquidating - stop loss")
s = f", , {self.holding.average_price + stop_loss_period}"
elif end_of_day:
self.exit_type = Exit.END_OF_DAY
self.csv_log(f"trade entered: liquidating - closing date at {closing_day}")
s = ", , "
if take_profit or stop_loss or end_of_day:
self.action_type = Action.CLOSED_SHORT_POSITION
self.liquidate(self._current_contract.symbol)
self.total_position = 0
self.summary_list[-1] += s
# ensures buying signal state is properly reset before going back to 5-minute bar
self.first_buy_condition = False
return
def _consolidation_handler(self, sender: object, bar: TradeBar) -> None:
"Handles 5-minute bar period."
# run code only from 12:00AM to 4:00PM regular trading hour
current_time = self.time
closing_day = self.market_close - datetime.timedelta(minutes=60)
opening_day = self.market_open + datetime.timedelta(minutes=150)
if current_time >= self.market_open and current_time <= self.market_close:
# manually update simple moving average and average true range
self._sma20.update(bar.end_time, bar.close)
self._atr.update(bar)
self._sma20_window.add(self._sma20.current.value)
if current_time < opening_day:
return
elif current_time >= opening_day and current_time < closing_day:
pass
else:
if self.live_mode:
self.log(f"{self.time}, Received data outside of running time from {opening_day} to {closing_day}")
return
# record bar data to enable access previous bar
self._trade_bar_window.add(bar)
previous_bar = self._trade_bar_window[1]
second_previous_bar = self._trade_bar_window[2]
# plot sharpe ratio
if self._sr.is_ready:
# The current value of self._sr is represented by self._sr.current.value
self.plot("SharpeRatio", "sr", self._sr.current.value)
self.current_sma20_value = self._sma20_window[0]
previous_sma20_value = self._sma20_window[1]
current_close_above_sma = bar.close > self.current_sma20_value
current_close_below_sma = bar.close < self.current_sma20_value
try:
previous_close_above_sma = previous_bar.close > previous_sma20_value
except:
previous_close_above_sma = None
try:
self.increasing_high = second_previous_bar.high < previous_bar.high and previous_bar.high < bar.high
except:
self.increasing_high = False
try:
self.decreasing_low = second_previous_bar.low > previous_bar.low and previous_bar.low > bar.low
except:
self.decreasing_low = False
# check for condition to increase position due to increasing high or decreasing low
if self.portfolio.invested:
self.bar_counter += 1
closing_trading_day = self.market_close - datetime.timedelta(minutes=60)
end_of_day = current_time > closing_trading_day
if self.holding.is_long and previous_close_above_sma is not None:
# increasing high
if self.increasing_high and self.bar_counter >= 3 and self.third_buy_condition:
self.action_type = Action.ADDED_TO_LONG
self.exit_type = ""
self.market_order(self._current_contract.symbol, self.half_contracts)
self.total_position = self.holding.average_price * self.holding.quantity
self.third_buy_condition = False
self.csv_log("trade entered: increasing three consecutive bar price's high")
return
if self.holding.is_short and previous_close_above_sma is not None:
# decreasing low
if self.decreasing_low and self.bar_counter >= 3 and self.third_sell_condition:
self.action_type = Action.ADDED_TO_SHORT
self.exit_type = ""
self.market_order(self._current_contract.symbol, -self.half_contracts)
self.total_position = self.holding.average_price * self.holding.quantity
self.third_sell_condition = False
self.csv_log("trade entered: decreasing three consecutive bar price's low")
return
if self.third_buy_condition or self.third_sell_condition:
self.csv_log("condition for increasing high or decreasing low not met")
else:
self.csv_log("Liquidation conditions not met")
return # prevents double buying/selling
closing_trading_day = self.market_close - datetime.timedelta(minutes=65)
last_trading_day = current_time > closing_trading_day
# Implement trading logic based on three buy/sell conditions
if previous_bar and not last_trading_day:
# Check if current price is above the SMA and higher than previous close with increased volume
current_price_above_sma = bar.close > self.current_sma20_value
higher_than_previous_close = bar.close > previous_bar.close
lower_than_previous_close = bar.close < previous_bar.close
increased_volume = bar.volume > previous_bar.volume
# first buy condition: price moves above the SMA from below
if not self.first_buy_condition:
if not previous_close_above_sma and current_price_above_sma: # increase price and volume condition
self.first_buy_condition = True
self.csv_log("first buying condition met")
else:
self.csv_log("first buying condition not met")
# second buying condition: the next bar has higher price & higher volume
# third buying condition: ATR must be less than to 6.75
elif self.first_buy_condition and higher_than_previous_close and increased_volume and self._atr.current.value < 6.75:
self._current_contract = self.securities[self._continuous_contract.mapped]
self.holding = self.portfolio[self._current_contract.symbol]
self.action_type = Action.BOUGHT_LONG
self.exit_type = ""
contracts = self.calculate_contracts()
self.market_order(self._current_contract.symbol, contracts)
self.total_position = self.holding.average_price * self.holding.quantity
self.csv_log("trade entered: all buying signal conditions met")
self.third_buy_condition = True
self.first_buy_condition = False
self.buy_atr = self._atr.current.value
self.bar_counter = 0
# reset state of first buy condition if second or third buying condition not met
else:
self.first_buy_condition = False
if not (higher_than_previous_close and increased_volume):
self.csv_log("second buying condition not met")
else:
self.csv_log("third buying condition not met")
# first sell condition: price moves below the SMA from above
if not self.first_sell_condition:
if previous_close_above_sma and not current_price_above_sma: # increase price and volume condition
self.first_sell_condition = True
self.csv_log("first selling condition met")
else:
self.csv_log("first selling condition not met")
# second selling condition: the next bar has lower price & higher volume
# third selling condition: ATR must be less than to 6.75
elif self.first_sell_condition and lower_than_previous_close and increased_volume and self._atr.current.value < 6.75:
self._current_contract = self.securities[self._continuous_contract.mapped]
self.holding = self.portfolio[self._current_contract.symbol]
self.action_type = Action.SOLD_SHORT
self.exit_type = ""
contracts = self.calculate_contracts()
self.market_order(self._current_contract.symbol, -contracts)
self.total_position = self.holding.average_price * self.holding.quantity
self.csv_log("trade entered: all selling signal conditions met")
self.third_sell_condition = True
self.first_sell_condition = False
self.sell_atr = self._atr.current.value
self.bar_counter = 0
# reset state of first sell condition if second and third selling condition not met
else:
self.first_sell_condition = False
if not (lower_than_previous_close and increased_volume):
self.csv_log("second selling condition not met")
else:
self.csv_log("third selling condition not met")
# def on_symbol_changed_events(self, symbol_changed_events):
# for symbol, changed_event in symbol_changed_events.items():
# old_symbol = changed_event.old_symbol
# new_symbol = changed_event.new_symbol
# quantity = self.portfolio[old_symbol].quantity
# # Rolling over: To liquidate the old mapped contract and switch to the new mapped contract.
# self.log(f"Rollover - Symbol changed at {self.time}: {old_symbol} -> {new_symbol}")
# self.liquidate(old_symbol)
# if quantity:
# self.market_order(new_symbol, quantity)
# self._current_contract = self.securities[self._continuous_contract.mapped]
# self.holding = self.portfolio[tself._current_contract.symbol]
def reset_values(self):
"Reset values so we start fresh"
self.__last = None
self._trade_bar_window.reset()
self._sma20_window.reset()
self.first_buy_condition = False
self.first_sell_condition = False
def on_data(self, data: Slice):
# opening_day = datetime.datetime(2025, 1, 7, 10, 21, 46, 939891)
# closing_day = datetime.datetime(2025, 1, 7, 10, 30, 0, 0)
# current_time = self.time
# quarter_hour = 31 # change from 0 to 31
# current_time = self.time
# opening_day = self.market_open + datetime.timedelta(minutes=quarter_hour*15)
# closing_day = self.market_open + datetime.timedelta(minutes=(quarter_hour+1)*15)
# half_hour = 14 # change from 0 to 14
# current_time = self.time
# opening_day = self.market_open + datetime.timedelta(minutes=half_hour*30)
# closing_day = self.market_open + datetime.timedelta(minutes=(half_hour+1)*30)
hour = 2 # change from 0 to 7
current_time = self.time
opening_day = self.market_open + datetime.timedelta(minutes=hour*60)
closing_day = self.market_open + datetime.timedelta(minutes=(hour+1)*60)
if current_time < opening_day or current_time >= closing_day:
return
# if not self.portfolio.invested:
# return
if not data.contains_key(self.sp500symbol):
return
if not self.is_market_open(self.sp500symbol):
return
ticks = data.ticks.get(self.sp500symbol, []) # Empty if not found
for tick in ticks:
if tick.quantity:
self.log(f", {tick.end_time}, {tick.price}, {tick.quantity}, {tick.exchange_code}")
# self._order_handler(tick)
return # check only a single tick
def on_end_of_algorithm(self) -> None:
# def generate_report(self):
"Create Log output for Summary"
pass
# self.log(", Trade Summary")
# self.log(f", Date, Time, Symbol, Fill Price, Quantity, PnL, Action, Exit Type, ATR, Order Fee, Portfolio Value, Take Profit Price, Stop Loss Price")
# for x in self.summary_list:
# self.log(", " + x)
# value_list = [float(value.split(",")[4]) for value in self.summary_list if len(value.split(",")) == 5]
# pnl = -sum(value_list)
# self.log(f", {self.time}, pnl:, {pnl}")
# self.log(", Margin Summary")
# self.log(f", Time, Portfolio Cash, Margin Used, Margin Remaining")
# for x in self.margin_list:
# self.log(", " + x)
# trades = self.trade_builder.closed_trades
# ts = TradeStatistics(trades)
# if trades:
# profitable_trades = list()
# losing_trades = list()
# breakeven_trades = list()
# for trade in trades:
# if trade.profit_loss > 0:
# profitable_trades.append(trade)
# elif trade.profit_loss < 0:
# losing_trades.append(trade)
# else:
# breakeven_trades.append(trade)
# gross_pnl = sum([trade.profit_loss for trade in trades])
# no_of_trades = len(trades)
# contracts = int(sum([trade.quantity for trade in trades]))
# time_trades = [trade.duration for trade in trades]
# copy_tt = copy.deepcopy(time_trades)
# time_trades.sort()
# sum_trades = sum(time_trades, datetime.timedelta())
# mean_time_trade = str(sum_trades / no_of_trades)
# trades_fees = sum([trade.total_fees for trade in trades])
# total_pnl = self.portfolio.total_net_profit
# currency = self.account_currency
# self.log("All TRADES")
# self.log(f"Gross P/L: {currency}{gross_pnl:.2f}")
# self.log(f"No. of Trades: {no_of_trades}")
# self.log(f"No. of Contracts: {contracts}")
# self.log(f"Average Trade Time: {mean_time_trade}")
# longest = time_trades[-1]
# self.log(f"Longest Trade Time: {longest}")
# win_percent = (len(profitable_trades)/no_of_trades)
# loss_percent = 1 - win_percent
# if profitable_trades:
# ave_win = sum([trade.profit_loss for trade in profitable_trades]) / len(profitable_trades)
# else:
# ave_win = 0
# if losing_trades:
# ave_loss = sum([trade.profit_loss for trade in losing_trades]) / len(losing_trades)
# else:
# ave_loss = 0
# self.log(f"Profitable Trades: {(len(profitable_trades)/no_of_trades):.0%}")
# self.log(f"Expectancy: {currency}{(win_percent * ave_win - loss_percent * ave_loss):.2f}")
# self.log(f"Trade Fees: {currency}{trades_fees:.2f}")
# self.log(f"Total PnL: {currency}{total_pnl:.2f}")
# sharpe = self.statistics.total_performance.portfolio_statistics.sharpe_ratio
# self.log(f"Sharpe Ratio: {sharpe:.2f}")
# self.log("Annual Trades")
# # We can access the statistics summary at runtime
# statistics = self.statistics.rolling_performances
# standard_list = [f"{kvp.key}: {kvp.value.portfolio_statistics.annual_standard_deviation:.4f}" for kvp in statistics if kvp.key.startswith("M1_")]
# profit_list = [f"{kvp.key}: {kvp.value.portfolio_statistics.total_net_profit:.4f}" for kvp in statistics if kvp.key.startswith("M1_")]
# sharpe_list = [f"{kvp.key}: {kvp.value.portfolio_statistics.sharpe_ratio:.4f}" for kvp in statistics if kvp.key.startswith("M1_")]
# for stat in sharpe_list:
# self.log(f"Sharpe Ratio: {stat}")
# for stat in standard_list:
# self.log(f"Standard Deviation: {stat}")
# for stat in profit_list:
# self.log(f"Net Profit: {stat}")
# trade_names = ("Winning", "Losing")
# stat_names = ("Max Run-up", "Max Drawdown")
# pnl_names = ("Profit", "Loss")
# trades_list = (profitable_trades, losing_trades)
# for index, trades in enumerate(trades_list):
# self.log(" ") # adds new line to log file
# if trades:
# profits = [trade.profit_loss for trade in trades]
# if index:
# profits.sort(reverse=True)
# else:
# profits.sort()
# time_trades = [trade.duration for trade in trades]
# time_trades.sort()
# run_ups = [(index, trade.mfe) for index, trade in enumerate(trades)]
# run_ups.sort(key=lambda x: x[1])
# i, max_run_up = run_ups[-1]
# max_trade = trades[i]
# self.log(f"{trade_names[index]} Trades")
# self.log(f"Total {pnl_names[index]}: {currency}{sum(profits):.2f}")
# self.log(f"No. of {trade_names[index]} Trades: {len(trades)}")
# self.log(f"No. of {trade_names[index]} Contracts: {int(sum([trade.quantity for trade in trades]))}")
# self.log(f"Largest {trade_names[index]} Trade: {currency}{profits[-1]:.2f}")
# self.log(f"Average {trade_names[index]} Trade: {currency}{fmean(profits):.2f}")
# self.log(f"Std. Dev. {trade_names[index]} Trade: {currency}{pstdev(profits):.2f}")
# self.log(f"Longest {trade_names[index]} Trade Time: {time_trades[-1]}")
# self.log(f"{stat_names[index]}: {currency}{max_run_up:.2f}")
# self.log(f"{stat_names[index]} from: {max_trade.entry_time}")
# self.log(f"{stat_names[index]} to: {max_trade.exit_time}")
# self.log("DAILY STATS")
# for cash in self.portfolio_cash_list:
# self.log(cash)
# for value in self.portfolio_value_list:
# self.log(value)
# for fee in self.trading_fees_list:
# self.log(fee)
# for info in self.sharpe_ratio_info:
# self.log(info)
# # add marker to seperate daily logs
# self.log("<END OF DAY>")
# self.log_header()
# self.summary_list = []
# self.margin_list = []
# self.portfolio_cash_list = []
# self.portfolio_value_list = []
# self.trading_fees_list = []