using cAlgo.API;
using cAlgo.API.Indicators;
using System;
using System.Collections.Generic;
namespace BTCUSDbot
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class BTCUSDbot : Robot
{
private TimeFrame higherTimeframe = TimeFrame.Weekly;
private double higherTimeframeThreshold = 0.5;
private double lotSize;
private MovingAverage fastMA;
private MovingAverage slowMA;
private DateTime lastBarTime;
private Color regularStopLossColor = Color.Red;
private Color trailingStopLossColor = Color.Blue;
private Color currentStopLossColor;
private double trailingStopDistanceInPips = 10000;
private double minProfitForTrailing = 10000; // Minimum profit in pips before trailing stop becomes active
private RelativeStrengthIndex rsi;
private double _volumeInUnits;
private AverageDirectionalMovementIndexRating _averageDirectionalMovementIndexRating;
[Parameter("Volume (Lots)", DefaultValue = 0.01)]
public double VolumeInLots { get; set; }
[Parameter("Label", DefaultValue = "Sample")]
public string Label { get; set; }
private int lookbackPeriod = 100;
double lowestLow;
double highestHigh;
bool calculateHighestHigh = false;
public Position[] BotPositions {
get
{
return Positions.FindAll(Label);
}
}
protected override void OnStart() {
int fastMAPeriod = 50;
int slowMAPeriod = 200;
int rsiPeriod = 14;
rsi = Indicators.RelativeStrengthIndex(Bars.ClosePrices, rsiPeriod);
fastMA = Indicators.MovingAverage(Bars.ClosePrices, fastMAPeriod, MovingAverageType.Simple);
slowMA = Indicators.MovingAverage(Bars.ClosePrices, slowMAPeriod, MovingAverageType.Simple);
lastBarTime = Bars.OpenTimes.LastValue;
_volumeInUnits = Symbol.QuantityToVolumeInUnits(VolumeInLots);
_averageDirectionalMovementIndexRating = Indicators.AverageDirectionalMovementIndexRating(25);
lowestLow = MarketSeries.Low.Minimum(lookbackPeriod);
highestHigh = MarketSeries.High.Maximum(lookbackPeriod);
}
protected override void OnBar() {
if(calculateHighestHigh == true) {
highestHigh = MarketSeries.High.Maximum(lookbackPeriod);
calculateHighestHigh = false;
}
if(Symbol.Bid < lowestLow){
highestHigh = lowestLow;
lowestLow = MarketSeries.Low.Minimum(lookbackPeriod);
Chart.DrawHorizontalLine("resistance line", highestHigh, Color.Gold, 1, LineStyle.LinesDots);
Chart.DrawHorizontalLine("support line", lowestLow, Color.White, 1, LineStyle.LinesDots);
}
if (Bars.OpenTimes.LastValue > lastBarTime) {
lastBarTime = Bars.OpenTimes.LastValue;
int index = Bars.ClosePrices.Count - 2; // Index of the last closed bar
bool isHigherTimeframeUptrend = IsHigherTimeframeUptrend();
foreach (var position in Positions) {
double unrealizedProfitInPips = position.Pips;
if (unrealizedProfitInPips >= minProfitForTrailing) {
string lineName = $"StopLossLine_{position.Id}";
double trailingStopPrice = Symbol.Bid - trailingStopDistanceInPips * Symbol.PipSize;
ModifyPosition(position, trailingStopPrice, position.TakeProfit);
currentStopLossColor = trailingStopLossColor;
Chart.RemoveObject(lineName);//for sl/tp lines
Chart.RemoveAllObjects();//for support/resistance
// Draw Stop Loss Line if it exists
if (position.StopLoss.HasValue) {
double stopLossPrice = position.StopLoss.Value;
Chart.DrawHorizontalLine(lineName, stopLossPrice, currentStopLossColor, 1, LineStyle.Solid);
}
}
if(!isHigherTimeframeUptrend && Positions.Count > 0)
{
ClosePosition(position);
Chart.RemoveAllObjects();
}
}
if(Symbol.Bid < highestHigh)
Chart.DrawHorizontalLine("support line", lowestLow, Color.White, 1, LineStyle.LinesDots);
Chart.DrawHorizontalLine("resistance line", highestHigh, Color.Gold, 1, LineStyle.LinesDots);
if(Symbol.Bid > highestHigh && fastMA.Result.HasCrossedAbove(slowMA.Result, index)&& isHigherTimeframeUptrend) {
ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.NormalizeVolumeInUnits(Symbol.LotSize), "Buy Order", 20000, 20000, null );
lowestLow = highestHigh;
calculateHighestHigh = true;
}
}
}
private void ClosePosition(TradeResult position)
{
ClosePosition(position);
}
private void ClosePositions(TradeType tradeType)
{
foreach (var position in BotPositions)
{
if (position.TradeType != tradeType) continue;
ClosePosition(position);
}
}
private bool IsHigherTimeframeUptrend() {
// Calculate moving averages on the higher timeframe
double[] higherTimeframeFastMASeries = CalculateSimpleMovingAverage(Bars.ClosePrices, higherTimeframe, 50);
double[] higherTimeframeSlowMASeries = CalculateSimpleMovingAverage(Bars.ClosePrices, higherTimeframe, 200);
int lastIndex = Bars.ClosePrices.Count - 1;
// Check if the slow MA on higher timeframe is below the fast MA, indicating a potential downtrend
return higherTimeframeSlowMASeries[lastIndex] < higherTimeframeFastMASeries[lastIndex];
}
private double[] CalculateSimpleMovingAverage(DataSeries source, TimeFrame timeframe, int period) {
double[] smaValues = new double[source.Count];
for (int i = 0; i < source.Count; i++)
{
if (i >= period - 1)
{
double sum = 0;
for (int j = i - period + 1; j <= i; j++)
{
sum += source[j];
}
smaValues[i] = sum / period;
}
else
{
smaValues[i] = source[i];
}
}
return smaValues;
}
}
}