Back

Feedback on improving my algo

Hi all

I managed to make the backtest work. My logic is that I am using my predictions of close, high and low based on a machine learning model to decide whether I am buying EURUSD, selling or both in a 1 hour timeframe. I want the take profit to be 80% of my predicted high and low respectively. The stop loss I want to be 200% of the difference between open and high and open and low respectively.

I am obviously newbie, so I am not sure if the code does what I want it to do. The returns are negative but my predictions are 0.1% accurate.

I set resolution to be .Hour so I assume onData runs every hour. Is this correct or am I better off with

self.Schedule.On

? If so, how can I say run every hour?

Also there is an OnOrderEvent that I assume runs whenever an order (Market, Limit or Stop) is made. I took this code from another thread in the forum.

Another issue I have is with price. I found in a thread that it is 

price = float(data["EURUSD"].Price)

Ideally I would like the price that my order was filled with because I want to set Take Profit and Stop Loss to be based on that.

There are a lot of self.log because I wanted a way to see what I am doing for debugging.

Any help will be appreciated.

Update Backtest








0

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.


I mean 0.1% error

0

Hi Georgios

.Welcome to QuantConnect.To ensure that your custom data is in sync with other data in the security universe, create a custom type. For further information, check out the documentation section on importing custom data.

In the attached backtest, I've demonstrated how you can import your custom data using the method I described. The logic in your strategy is the same as before to produce a buy signal. However, you need to add the other leg of the strategy to emit a sell signal. Also, I've demonstrated how to use an average fill price for take-profit and stop-loss order instead of using the current price.The following code snippet in the attached backtest will make sure you get hourly data in OnData():

# Add custom data to security universe
self.AddData(predEURUSD, "predEURUSD", Resolution.Hour)
# Add EUR/USD currency pair to security universe
self.AddForex("EURUSD", Resolution.Hour, Market.Oanda)

The hourly data resolution can be changed to daily data resolution by setting Resolution.Hour to Resolution.Daily. Good luck!

1


  Halldor Andersen thank you very much for your help. I didn't know that importing data as custom data is better.

My remaining questions are:

1. How do I set quantity to buy as % of balance? In 

self.Buy("EURUSD", 100)

what is the unit of measurement of "100"?

2. How can I have buy and sell orders open at the same time?

3. Is the code for bracket orders working?

Thanks in advance

 
0

Hi Georgios.

1.  Quantity of 100 means that you are buying 100 Euros in exchange for U.S. dollars. You can use the method CalculateOrderQuantity() to calculate quantity with a specific portfolio value allocation target in mind. For example, to buy Euros for 50% of the value of your portfolio:

quantity = self.CalculateOrderQuantity("EURUSD",0.5)
self.Buy("EURUSD", quantity)

You can also use SetHoldings:

self.SetHoldings("EURUSD",0.5)

2. You can submit buy order and sell order simultaneously. However, you will have a net exposure to security, depending on the size of your orders.

3. The following code snippet that you are using in your code will cancel the remaining order if either stop-loss or take-profit is triggered, so the "bracket" orders should work.

def OnOrderEvent(self, orderEvent):
order = self.Transactions.GetOrderById(orderEvent.OrderId)

if order.Status == OrderStatus.Filled:
if order.Type == OrderType.Limit or order.Type == OrderType.Limit:
self.Transactions.CancelOpenOrders(order.Symbol)

if order.Status == OrderStatus.Canceled:
self.Log(str(orderEvent))

 

1

@Halldor Andersen thanks again for your answers. I tried to attach the latest backtest with relatively good results after incorporating your feedback but the app hangs.

However, I think that the orders are executed not in the way I intend. It seems to me that stop loss and take profit are taken into consideration while the order remains unfilled. I want the order to be like in Metatrader, where a position is opened and closed when the stop loss or take profit level is reached or when there is not enough fund due to opposite direction.

Have I got it right?

0

Here is the code because I can't make attaching backtest work

import numpy as np
import pandas as pd
from QuantConnect.Data import SubscriptionDataSource
from QuantConnect.Python import PythonData
from datetime import date, timedelta, datetime
from decimal import Decimal

### <summary>
### Basic template algorithm simply initializes the date range and cash. This is a skeleton
### framework you can use for designing an algorithm.
### </summary>
class BasicTemplateAlgorithm(QCAlgorithm):
'''Basic template algorithm simply initializes the date range and cash'''

def Initialize(self):
'''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''

self.SetStartDate(2017,1, 10) #Set Start Date
self.SetEndDate(2018,12,31) #Set End Date
self.SetCash(10000) #Set Strategy Cash
# Find more symbols here: http://quantconnect.com/data
self.AddForex("EURUSD", Resolution.Hour, Market.Oanda)
self.AddData(predEURUSDASK, "predEURUSDASK", Resolution.Hour)
self.AddData(predEURUSDBID, "predEURUSDBID", Resolution.Hour)
self.SetTimeZone("Etc/GMT0")
#self.Schedule.On(self.DateRules.EveryDay("EURUSD"), self.TimeRules.Every("Hour"), self.EveryHour)
self.spmulti = self.GetParameter("SPmulti")
self.tpmulti = self.GetParameter("TPmulti")
self.Debug("Everything loaded")

def OnData(self, data):
'''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.

Arguments:
data: Slice object keyed by symbol containing the stock data
'''
if not data.ContainsKey("predEURUSDASK") or not data.ContainsKey("predEURUSDBID") or not data.ContainsKey("EURUSD"): return
quoteBar = data['EURUSD']
self.Log(f"Time: {quoteBar.EndTime}") #The time the period closes
self.Log(f"Open: {quoteBar.Open}")
# Retrieve High Ask Price from object
highASK=data["predEURUSDASK"].Value
self.Log(f"High ASK: {highASK}")
# User variables
highASKOpendiff = highASK- quoteBar.Open
self.Log(f"highASKOpendiff: {highASKOpendiff}")
BuyTPASK=highASKOpendiff*0.8
self.Log(f"BuyTPASK: {BuyTPASK}")
BuySLASK=highASKOpendiff*5
self.Log(f"BuySLASK: {BuySLASK}")
# Retrieve Low Bid Price from object
lowBID=data["predEURUSDBID"].Value
self.Log(f"Low BID: {lowBID}")
# User variables
OpenLowBIDdiff = quoteBar.Open - lowBID
self.Log(f"OpenLowBIDdiff: {OpenLowBIDdiff}")
SellTPBID=OpenLowBIDdiff*0.8
self.Log(f"SellTPBID: {SellTPBID}")
SellSLBID=OpenLowBIDdiff*5
self.Log(f"SellSLBID: {SellSLBID}")
#if sum(highASK.notna()) >=1 & sum(lowBID.notna()) >=1 :
if highASKOpendiff > 0.0015:
self.Buy("EURUSD", 1000)
averageFillPrice = self.Portfolio["EURUSD"].AveragePrice
self.LimitOrder("EURUSD", -1000, (averageFillPrice +BuyTPASK))
self.StopMarketOrder("EURUSD", -1000, (averageFillPrice -BuySLASK))
if OpenLowBIDdiff > 0.0015:
self.Sell("EURUSD", 1000)
averageFillPrice = self.Portfolio["EURUSD"].AveragePrice
self.LimitOrder("EURUSD", 1000, (averageFillPrice -SellTPBID))
self.StopMarketOrder("EURUSD", 1000, (averageFillPrice + SellSLBID))

def OnOrderEvent(self, orderEvent):
order = self.Transactions.GetOrderById(orderEvent.OrderId)

if order.Status == OrderStatus.Filled:
if order.Type == OrderType.Limit or order.Type == OrderType.StopMarket:
self.Transactions.CancelOpenOrders(order.Symbol)

if order.Status == OrderStatus.Canceled:
self.Log(str(orderEvent))

def EveryHour(self):
pass


class predEURUSDASK(PythonData):
#"Import custom data from a csv file"
def GetSource(self, config, date, isLiveMode):
return SubscriptionDataSource("http://sensedrive.science/files/EURUSD1H_CHL_ASK_cat.csv", SubscriptionTransportMedium.RemoteFile)
def Reader(self, config, line, date, isLiveMode):
if not (line.strip() and line[0].isdigit()): return None
index = predEURUSDASK()
index.Symbol = config.Symbol
try:
data = line.split(',')

index.Time = datetime.strptime(data[0], "%Y-%m-%d %H:%M:%S")

### Retrieve "predicted" High Ask Price
index.Value = Decimal(data[2])

except:
return None
return index

class predEURUSDBID(PythonData):
#"Import custom data from a csv file"
def GetSource(self, config, date, isLiveMode):
return SubscriptionDataSource("http://sensedrive.science/files/EURUSD1H_CHL_BID_cat.csv", SubscriptionTransportMedium.RemoteFile)
def Reader(self, config, line, date, isLiveMode):
if not (line.strip() and line[0].isdigit()): return None
index = predEURUSDBID()
index.Symbol = config.Symbol
try:
data = line.split(',')

index.Time = datetime.strptime(data[0], "%Y-%m-%d %H:%M:%S")

### Retrieve "predicted" High Ask Price
index.Value = Decimal(data[2])

except:
return None
return index

 

0

Hi Georgios.

It seems that your custom data is no longer available in the cloud.

These two links are not active:

http://sensedrive.science/files/EURUSD1H_CHL_ASK_cat.csv

http://sensedrive.science/files/EURUSD1H_CHL_BID_cat.csv

Lack of data is currently the reason why the algorithm places no trades.

0

Update Backtest





0

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.


Loading...

This discussion is closed