search Nothing found
Main Algotrading documentation Getting Started

Create a new robot

Introduction

 To build a trading robot, we need to have a trading strategy that we want to automate.

 We will write a small technical task in which we will define all the conditions for opening and closing positions.

 For example, let's take a simple trading strategy based on the "Hammer" ("Inverted hammer") pattern.

 Visually, this pattern resembles a hammer hanging on clamps with the handle down: the lower shadow is the handle, the body is the shock part, the upper shadow is the end of the handle protruding from the shock part.

 General conditions:

 There should be no open positions in the market.

Conditions for selling:

  1. high2>high3
  2. high1>high2
  3. close1<open1
  4. ((open1-low1)/(high1-low1))<=F(%),

where F is a criterion for the quality of the "hammer" candlestick

 Conditions for buying: 

  1. low2<high3
  2. high1<high2
  3. close1>open1
  4. ((high1-open1)/(high1-low1))<=F(%), 

where F is a criterion for the quality of the "hammer" candlestick

 Create a new robot

 Enter the name of the robot and click the "Create" button

 The program will create a standard template with three event handling functions: OnStart(), OnTick() and OnStop().

 Input parameters

 Let's move on to creating external variables so that the user has the opportunity to set up his own parameters for the robot.

  • Lot — a trading lot with which a position will be opened. By default, we set it up to the minimum. The variable type will be double, because this lot cannot be an integer.
  • Stop Loss — (loss limit) for each position of the robot. The default is set in points. The variable type will be int. since it's an integer.
  • Take Profit - needed to close a position when a given profit is reached. The default is set in points. The variable type will be int. since it's an integer.
  • Parameter F (%) — “Hammer” candlestick quality parameter. The variable type will be int. since it's an integer.

The first three parameters are necessary even for the simplest robot. So that they can be seen when setting up the robot as input parameters, we will use the public modifier, which will define our variables as external. This block of code is written at the beginning of the editor.

using System;
using System.Runtime.InteropServices;
namespace uAlgo.Bots
{
public class NewBot : Bot
{
// Input parameters
//Lot
[Parameter("Lot", MinValue = 0.1, MaxValue = 50)]
public double Lot = 0.1;
// StopLoss
[Parameter("StopLoss (pips)", MinValue = 1, MaxValue = 1000)]
public int StopLossPips = 300;
// TakeProfit
[Parameter("TakeProfit (pips)", MinValue = 1, MaxValue = 1000)]
public int TakeProfitPips = 300;
// “hammer” candlestick quality parameter
[Parameter("Parameter F (%)", MinValue = 1, MaxValue = 50)]
public int F = 50;
public void OnTick()
{
// Put your core logic here
}
public void OnStart()
{
// Put your initialization logic here
}
public void OnStop()
{
// Put your deinitialization logic here
}
}
}

Let's create a user GetSignal() function 

The conditions for entering the market are defined in the formulation, and now it is necessary to explain them to the trading robot. This function will check the conditions and return “buy” or “sell” signals to us.

private string GetSignal()
{
string signal = "";
int err;
Bar[] rates;

err = Bars.Select(Symbol.SymbolName, TimeFrame.Current, 4, out rates);
// Conditions for selling (Uptrend.)
if (rates[3].High < rates[2].High) {
if (rates[2].High < rates[1].High) {
if (rates[1].Close < rates[1].Open && (rates[1].High - rates[1].Low) > 0) {
if ((((rates[1].Open - rates[1].Low) / (rates[1].High - rates[1].Low)) * 100) <= F) {
signal = "sell";
}
}
}
}
// Conditions for buying (Downtrend.)
if (rates[3].Low > rates[2].Low) {
if (rates[2].Low > rates[1].Low) {
if (rates[1].Close >= rates[1].Open && (rates[1].High - rates[1].Low) > 0) {
if ((((rates[1].High - rates[1].Open) / (rates[1].High - rates[1].Low)) * 100) <= F) {
signal = "buy";
}
}
}
}
return(signal);
}

We have reached the OnTick() function. In it, the further code will complete its cycle every tick. In accordance with our formulation, we must first check that there are no open positions in the market for this robot by the current symbol. To do this, let's write a user GetPositionCount() function that will return the number of open positions.

private int GetPositionCount()
{
int poc = 0;
for (var i = Positions.Count - 1; i >= 0; i--) {
Position pos = Positions.Find(Positions[i].PositionId);
if (pos != null) {
if (pos.SymbolName == Symbol.SymbolName) {
if ((pos.PositionType == (int)PositionType.Buy || pos.PositionType == (int)PositionType.Sell)) {
poc++;
}
}
}
}
return(poc);
}

In OnTick() we will call the GetSignal() function and open buy or sell positions.

It will look like this:

public void OnTick()
{
int err;
int id;
if (GetPositionCount() == 0) {
if (GetSignal() == "buy") {
// buying
err = Positions.Open(Symbol.SymbolName, PositionType.Buy, Lot, 0, 0, TakeProfitPips, StopLossPips, "hammer", out id);
if (err > 0) {
Print("log.txt", "error: " + err.ToString());
}
}
if (GetSignal() == "sell") {
// selling
err = Positions.Open(Symbol.SymbolName, PositionType.Sell, Lot, 0, 0, TakeProfitPips, StopLossPips, "hammer", out id);
if (err > 0) {
Print("log.txt", "error: " + err.ToString());
}
}
}
}

Trade request error checking

When sending a request to the server, it is recommended to check trade requests for errors; to do this, we will write the error code to err variable in case of an unsuccessful request. Let's create a Print function that will write errors to our log. We will pass 2 parameters to the function (file name for logging information and a string for writing to a file).

private void Print(string f, string l)
{
// we get the path to the folder with our robot
string AssemblyPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + Path.DirectorySeparatorChar.ToString();
// full path to the file for recording service information
string mLog = AssemblyPath + f;

using (StreamWriter sw = new StreamWriter(mLog, true))
sw.WriteLine(l);
}

Putting everything described above together, we get a ready-made robot that will trade according to our trading strategy.

using System;
using System.Runtime.InteropServices;
using System.IO;
using System.Reflection;

namespace uAlgo.Bots
{
public class NewBot : Bot
{
// Input parameters
//Lot
[Parameter("Lot", MinValue = 0.1, MaxValue = 50)]
public double Lot = 0.1;
// StopLoss
[Parameter("StopLoss (pips)", MinValue = 1, MaxValue = 1000)]
public int StopLossPips = 300;
// TakeProfit
[Parameter("TakeProfit (pips)", MinValue = 1, MaxValue = 1000)]
public int TakeProfitPips = 300;
// “hammer” candlestick quality parameter
[Parameter("Parameter F (%)", MinValue = 1, MaxValue = 50)]
public int F = 50;

//-------------------------------------
//
//-------------------------------------
private string GetSignal()
{
string signal = "";
int err;
Bar[] rates;

err = Bars.Select(Symbol.SymbolName, TimeFrame.Current, 4, out rates);
// Conditions for selling (Uptrend.)
if (rates[3].High < rates[2].High) {
if (rates[2].High < rates[1].High) {
if (rates[1].Close < rates[1].Open && (rates[1].High - rates[1].Low) > 0) {
if ((((rates[1].Open - rates[1].Low) / (rates[1].High - rates[1].Low)) * 100) <= F) {
signal = "sell";
}
}
}
}
// Conditions for buying (Downtrend.)
if (rates[3].Low > rates[2].Low) {
if (rates[2].Low > rates[1].Low) {
if (rates[1].Close >= rates[1].Open && (rates[1].High - rates[1].Low) > 0) {
if ((((rates[1].High - rates[1].Open) / (rates[1].High - rates[1].Low)) * 100) <= F) {
signal = "buy";
}
}
}
}
return(signal);
}
//-------------------------------------
//
//-------------------------------------
private int GetPositionCount()
{
int poc = 0;
for (var i = Positions.Count - 1; i >= 0; i--) {
Position pos = Positions.Find(Positions[i].PositionId);
if (pos != null) {
if (pos.SymbolName == Symbol.SymbolName) {
if ((pos.PositionType == (int)PositionType.Buy || pos.PositionType == (int)PositionType.Sell)) {
poc++;
}
}
}
}
return(poc);
}

//-------------------------------------
//
//-------------------------------------
private void Print(string f, string l)
{
// we get the path to the folder with our robot
string AssemblyPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + Path.DirectorySeparatorChar.ToString();
// full path to the file for recording service information
string mLog = AssemblyPath + f;

using (StreamWriter sw = new StreamWriter(mLog, true))
sw.WriteLine(l);
}

public void OnTick()
{
int err;
int id;
if (GetPositionCount() == 0) {
if (GetSignal() == "buy") {
// buying
err = Positions.Open(Symbol.SymbolName, PositionType.Buy, Lot, 0, 0, TakeProfitPips, StopLossPips, "hammer", out id);
if (err > 0) {
Print("log.txt", "error: " + err.ToString());
}
}
if (GetSignal() == "sell") {
// selling
err = Positions.Open(Symbol.SymbolName, PositionType.Sell, Lot, 0, 0, TakeProfitPips, StopLossPips, "hammer", out id);
if (err > 0) {
Print("log.txt", "error: " + err.ToString());
}
}
}
}

public void OnStart()
{
// Put your initialization logic here
}

public void OnStop()
{
// Put your deinitialization logic here
}
}
}

Before you can use your robot in trading, you need to compile your source code into an executable. To do this, click the "Build" button and look at the build result window. If there are no errors in the code, then you will see the message "Build succeeded", which means that the robot has been successfully built and is ready for trading.