import pandas as pd
from datetime import datetime
class FXMomentumAlgorithm(QCAlgorithm):
def Initialize(self):
# self.SetStartDate(2019, 1, 5)
# self.SetEndDate(datetime.now())
self.SetStartDate(2022, 2, 3)
self.SetEndDate(2022, 2, 9)
self.SetCash(100000)
self.resolution = Resolution.Minute
self.pair = 'USDCHF'
self._orders = 0
self._grid_number = 2
# self._grid_number = 20
self._reference_price = None
self._std = None
self.AddForex(self.pair, self.resolution, Market.Oanda)
self.SetBenchmark(self.pair)
################################################
# Add Charting
self._my_chart = Chart('Indicator')
self._my_chart.AddSeries(Series("Cash", SeriesType.Line, 0))
self.AddChart(self._my_chart)
self._my_chart2 = Chart('Orders')
self._my_chart2.AddSeries(Series("Cash", SeriesType.Bar, 0))
self.AddChart(self._my_chart2)
self.Schedule.On(self.DateRules.EveryDay(self.pair), self.TimeRules.AfterMarketOpen(self.pair), self.openMarket)
self.Schedule.On(self.DateRules.EveryDay(self.pair), self.TimeRules.BeforeMarketClose(self.pair), self.closeMarket)
def OnData(self, data):
# invested_symbols = [symbol for symbol, holding in self.Portfolio.items() if holding.Invested]
# if data[self.pair].Close < (self._reference_price - self._std) and self.pair not in invested_symbols:
# # self.SetHoldings(self.pair, 1)
# self._qty = self.CalculateOrderQuantity(self.pair, 1)
# self.MarketOrder(self.pair, self._qty, self._reference_price - self._std)
# elif data[self.pair].Close > (self._reference_price + self._std) and self._qty != 0:
# self.Liquidate(self.pair)
# self.Plot('Indicator', 'Open + STD', self._reference_price + self._std)
# self.Plot('Indicator', 'Open - STD', self._reference_price - self._std)
# self.Plot('Indicator', 'Close', data[self.pair].Close)
# self.Plot('Orders', 'Orders', len([symbol for symbol, holding in self.Portfolio.items() if holding.Invested]) - self._orders)
# self._orders = len([symbol for symbol, holding in self.Portfolio.items() if holding.Invested])
pass
def setParameters(self):
# ? Should we calculate this std the next day or right after the market is closed?
history = self.History([self.pair], 1440, self.resolution)
history = history.droplevel(0)
# Locate the previous market open date
for d in reversed(pd.date_range(start=history.index[0], end=history.index[-1], freq='D')):
if d.weekday() not in [5, 6]:
# self.Debug(f'{d}, {d.weekday()}')
tgt = d
break
his = history[(history.index.day == tgt.day) & (history.index.year == tgt.year) & (history.index.month == tgt.month)]
# Get volatility of previous day
self._std = his.high.max() - his.low.min()
# Get close of previous day
self._reference_price = his.close[-1]
# self.Debug(f'Reference price: {self._reference_price}')
def openMarket(self):
# self.Debug(f'{self.Time} Market start')
self.setParameters()
# self._qty = self.CalculateOrderQuantity(self.pair, 0.49)
qty = (self.Portfolio.Cash / self._grid_number) / (self._reference_price - self._std / self._grid_number)
self.LimitOrder(
self.pair,
qty,
round(self._reference_price - self._std / self._grid_number, 5),
'Long1'
)
qty = (self.Portfolio.Cash / self._grid_number) / (self._reference_price - self._std)
self.LimitOrder(
self.pair,
qty,
round(self._reference_price - self._std, 5),
'Long2'
)
qty = (self.Portfolio.Cash / self._grid_number) / (self._reference_price + self._std / self._grid_number)
self.LimitOrder(
self.pair,
-qty,
round(self._reference_price + self._std / self._grid_number, 5),
'Short1'
)
qty = (self.Portfolio.Cash / self._grid_number) / (self._reference_price + self._std)
self.LimitOrder(
self.pair,
-qty,
round(self._reference_price + self._std, 5),
'Short2'
)
def closeMarket(self):
# self.Debug(f'{self.Time} Market close')
# Liquidate all positions by the end of the day
self.Liquidate(self.pair)
def OnOrderEvent(self, orderEvent):
order = self.Transactions.GetOrderById(orderEvent.OrderId)
if orderEvent.Status == OrderStatus.Filled:
self.Debug(
"{0}: {1} ({2})".format(
self.Time,
orderEvent,
order.Tag
)
)
if order.Tag == 'Long1':
self.LimitOrder(
self.pair,
-order.Quantity,
round(self._reference_price, 5),
'Long1-Liquidate'
)
elif order.Tag == 'Long2':
self.LimitOrder(
self.pair,
-order.Quantity,
round(self._reference_price - self._std / self._grid_number, 5),
'Long2-Liquidate'
)
elif order.Tag == 'Short1':
self.LimitOrder(
self.pair,
order.Quantity,
round(self._reference_price, 5),
'Short1-Liquidate'
)
elif order.Tag == 'Short2':
self.LimitOrder(
self.pair,
order.Quantity,
round(self._reference_price + self._std / self._grid_number, 5),
'Short2-Liquidate'
)
# Others:
# if order.Type == OrderType.Limit or order.Type == OrderType.StopMarket:
# self.Transactions.CancelOpenOrders(order.Symbol)