Bot Code Example
MACD Bot Example
using System;
using System.Collections.Generic;
using Skender.Stock.Indicators;
using System.Linq;
using SharpTraderBot;
namespace SharpTraderArb.Strategies
{
public class MACDBot: Bot
{
//input parameters
[PropertyInfo("EURUSD", "Trading symbol")]
public string Symbol {get;set;} = "EURUSD";
[PropertyInfo(TimeFrame.M30, "Timeframe")]
public TimeFrame Period {get;set;} = TimeFrame.M30;
[PropertyInfo(50, "Take profit")]
public double TakeProfit {get;set;} = 50;
[PropertyInfo(0.1, "Lot size")]
public double Lots {get;set;} = 0.1;
[PropertyInfo(30, "Trailing stop")]
public double TrailingStop {get;set;} = 30;
[PropertyInfo(3, "MACD open level")]
public double MACDOpenLevel {get;set;} = 3;
[PropertyInfo(2, "MACD close level")]
public double MACDCloseLevel {get;set;} = 2;
[PropertyInfo(30, "Moving average period")]
public int MATrendPeriod {get;set;} = 26;
//internal variables
string positionID = "";
double pointValue = 1e-5;
double bid,ask;
string clienOrderId = "";
public override void OnInit()
{
pointValue = ticker.getPointValue(0, Symbol);
//check for opened position
STPosition buyPosition = getPositionByComment("MACD_buy", 0);
if (buyPosition != null)
positionID = buyPosition.PositionId;
STPosition sellPosition = getPositionByComment("MACD_sell", 0);
if (sellPosition != null)
positionID = sellPosition.PositionId;
}
public override void OnDeinit()
{
}
public override void OnTick(NewTickEventArgs args)
{
if (clienOrderId != "") // order is already processing, exit
return;
if (ticker.getSymbolName(0,Symbol) != args.tick.symbol)//tick on another symbol
return;
double MacdCurrent,MacdPrevious;
double SignalCurrent,SignalPrevious;
double MaCurrent,MaPrevious;
var MACDmain = indicators.iMACD(0, Symbol,Period,PriceUsed.Close,MACDMode.Main);
if (MACDmain == null)
{
stopBot();
return;
}
MacdCurrent = (double)MACDmain[0];
MacdPrevious = (double)MACDmain[1];
var MACDsignal = indicators.iMACD(0, Symbol,Period,PriceUsed.Close,MACDMode.Signal);
if (MACDsignal == null)
{
stopBot();
return;
}
SignalCurrent = (double)MACDsignal[0];
SignalPrevious = (double)MACDsignal[1];
var MA = indicators.iEMA(0,Symbol,Period,PriceUsed.Close,MATrendPeriod);
if (MA == null)
{
stopBot();
return;
}
MaCurrent = (double)MA[0];
MaPrevious = (double)MA[1];
bid = ticker.getBid(0, Symbol);
ask = ticker.getAsk(0, Symbol);
//writeLog(bid.ToString());
if(positionID == "")// no opened positions - check for entry condition
{
writeLog("Time to buy!");
clienOrderId = sendOrder(0,Symbol,Lots, OrderSide.BUY,OrderType.MARKET, ask,"MACD_buy");
return;
}
else // we have opened position
{
STPosition position = getPositionByID(positionID);
if (position == null)// this position is already closed
{
positionID = "";
return;
}
if(position.side == OrderSide.BUY)//we have buy position opened
{
//setting position take profit value (if not set)
if (position.takeProfit == 0)
modifyPositionByID(positionID, position.stopLoss, position.openPrice + TakeProfit * pointValue);
//--- checking closing conditions
if(MacdCurrent > 0 && MacdCurrent < SignalCurrent && MacdPrevious > SignalPrevious && MacdCurrent>(MACDCloseLevel * pointValue))
{
clienOrderId = closePositionByID(positionID);
return;
}
//--- perform trailing
if(TrailingStop > 0)
{
if(bid - position.openPrice > pointValue * TrailingStop)
{
if(position.stopLoss < bid-pointValue * TrailingStop)
{
modifyPositionByID(positionID, bid-pointValue * TrailingStop, position.takeProfit);
return;
}
}
}
}
else //we have sell position opened
{
//setting position take profit value (if not set)
if (position.takeProfit == 0)
modifyPositionByID(positionID, position.stopLoss, position.openPrice - TakeProfit * pointValue);
//--- checking closing conditions
if(MacdCurrent < 0 && MacdCurrent > SignalCurrent && MacdPrevious < SignalPrevious && Math.Abs(MacdCurrent) > (MACDCloseLevel * pointValue))
{
clienOrderId = closePositionByID(positionID);
return;
}
//--- check for trailing stop
if(TrailingStop > 0)
{
if((position.openPrice - ask) > (pointValue * TrailingStop))
{
if((position.stopLoss > (ask + pointValue * TrailingStop)) || (position.stopLoss == 0))
{
modifyPositionByID(positionID, ask + pointValue * TrailingStop, position.takeProfit);
return;
}
}
}
}
}
}
public override void OnPositionOpened(PositionOpenedEventArgs args)
{
writeLog($"Position {args.position.PositionId} was opened");
clienOrderId = "";
positionID = args.position.PositionId;
}
public override void OnPositionClosed(PositionClosedEventArgs args)
{
writeLog($"Position {args.position.PositionId} was closed");
positionID = "";
clienOrderId = "";
}
public virtual void OnOrderStatusUpdate(STOrder order)
{
if (order.clientOrderId == clienOrderId && (order.status == OrderStatus.CANCELED || order.status == OrderStatus.REJECTED))
{
writeLog($"Order {clienOrderId} was rejected with reason {order.comment}");
clienOrderId = "";
}
}
}
}