Topics
Forum Topics not found
Replies
amusleh
01 Nov 2021, 08:19
Hi,
Try this:
using cAlgo.API;
using cAlgo.API.Indicators;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class NewcBot : Robot
{
private ExponentialMovingAverage _ema;
protected override void OnStart()
{
_ema = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 200);
}
protected override void OnBar()
{
if (Bars.ClosePrices.Last(1) > _ema.Result.Last(1))
{
// Buy
}
else if (Bars.ClosePrices.Last(1) < _ema.Result.Last(1))
{
// Sell
}
}
}
}
@amusleh
amusleh
29 Oct 2021, 08:52
Hi,
You can easily change Lots to Units, use Symo QuantityToVolumeInUnits method.
@amusleh
amusleh
29 Oct 2021, 08:50
Hi,
Please learn basics of C# before developing indicators/cBot.
For date and time you can use C# DateTime, DateTimeOffset, and TimeSpan types.
To get time from user via a parameter you can use string for parameter type and then parse it to any of the above mentioned types.
@amusleh
amusleh
27 Oct 2021, 11:56
Hi,
The original position ID is on the comment of opposite position, so you can match them by using the opposite position comment and the original position ID.
To get original position ID from opposite position you can split its comment with "_", the second value will be ID, then parse the ID with long.Parse and then you can compare it with original position ID for matching.
foreach (var pos in positionsCopy)
{
// if position comment is empty then skip it
if (string.IsNullOrWhiteSpace(pos.Comment)) continue;
var commentSplit = pos.Comment.Split('_');
if (commentSplit.Length < 2) continue;
var originalPositionIdString = commentSplit[1];
long originalPositionId;
if (!long.TryParse(originalPositionIdString, out originalPositionId)) continue;
var originalPosition = Positions.FirstOrDefault(position => position.Id == originalPositionId);
if (originalPosition == null) continue;
// Now you have the original position on originalPosition variable
}
@amusleh
amusleh
27 Oct 2021, 08:30
( Updated at: 27 Oct 2021, 08:31 )
Hi,
No, you can't get the angle from API, but you can calculate it if you want to:
private double GetAngle(ChartTrendLine trendLine)
{
var x1 = Bars.OpenTimes.GetIndexByTime(trendLine.Time1);
var x2= Bars.OpenTimes.GetIndexByTime(trendLine.Time2);
double xDiff = x2 - x1;
var yDiff = trendLine.Y2 - trendLine.Y1;
return Math.Atan2(yDiff, xDiff) * 180.0 / Math.PI;
}
The above method will return the angle of a trend line in Degree, it will not work properly if your trend line is drawn in future time, because it uses bar indices for x axis.
If you to get the angle from API then please open a thread on forum suggestions section.
@amusleh
amusleh
27 Oct 2021, 08:20
Hi,
The code I posted opens an opposite position for each of your bot positions based on given condition.
What do you mean by lots of positions? do you want to set a maximum position number?
If you can tell us what exactly you want to implement on your cBot then I will be able to help you.
@amusleh
amusleh
26 Oct 2021, 09:22
( Updated at: 26 Oct 2021, 09:23 )
Hi,
Try this:
private double GetMax(DateTime startTime, DateTime endTime)
{
var startBarIndex = Bars.OpenTimes.GetIndexByTime(startTime);
var endBarIndex = Bars.OpenTimes.GetIndexByTime(endTime);
var max = double.MinValue;
for (var barIndex = startBarIndex; barIndex <= endBarIndex; barIndex++)
{
max = Math.Max(Bars.HighPrices[barIndex], max);
}
return max;
}
private double GetMin(DateTime startTime, DateTime endTime)
{
var startBarIndex = Bars.OpenTimes.GetIndexByTime(startTime);
var endBarIndex = Bars.OpenTimes.GetIndexByTime(endTime);
var min = double.MaxValue;
for (var barIndex = startBarIndex; barIndex <= endBarIndex; barIndex++)
{
min = Math.Min(Bars.LowPrices[barIndex], min);
}
return min;
}
This should work on all chart types as long as the data is available on your chart in between start and end time.
@amusleh
amusleh
26 Oct 2021, 09:15
Hi,
You should use OnTick not OnBar, and the issue with your code is that you are opening multiple opposite positions for a single position, try this:
using System;
using System.Linq;
using cAlgo.API;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class NewcBot : Robot
{
protected override void OnTick()
{
CreateOpposite();
}
private void CreateOpposite()
{
var positionsCopy = Positions.ToArray();
foreach (var pos in positionsCopy)
{
var comment = string.Format("Opposite_{0}", pos.Id);
if (Positions.Any(position => string.Equals(position.Comment, comment, StringComparison.OrdinalIgnoreCase)))
{
continue;
}
var sym = pos.SymbolName;
var type = pos.TradeType;
var cmd = pos.Comment;
var ov = pos.VolumeInUnits;
double atr = ATR[sym].Result.LastValue;
if (type == TradeType.Buy && pos.Pips <= -5 * atr)
{
ExecuteMarketOrder(TradeType.Sell, sym, ov, "EA", 0, 0, comment);
}
if (type == TradeType.Sell && pos.Pips <= -5 * atr)
{
ExecuteMarketOrder(TradeType.Buy, sym, ov, "EA", 0, 0, comment);
}
}
}
}
}
I use comment to prevent opening multiple opposite positions for a single position, each position will have only one opposite position.
@amusleh
amusleh
25 Oct 2021, 09:53
Hi,
MarketSeries is obsolete, you should use Bars: cAlgo API Reference - Bars Interface (ctrader.com)
To get lowest price in last 20 bars you can use Bars.LowPrices.Minimum(20).
@amusleh
amusleh
25 Oct 2021, 09:51
RE: RE:
velu130486 said:
Hi Ahmad,
Thanks for your reply. Actually my request is to double the volume on every 4th position count not based on time.
Because sometimes my bot create more than 4 - 6 positions within a hour depends on moving average signal. So the volume is increased on each and every position which I would like to control it, so I would like to increase the volume only on 4,8,12,16 position for both buy and sell positions etc.,
Thanks and Regards
R. Vadivelan
amusleh said:
Hi,
You can use timer, set the interval to 4 hours and double the volume whenever the timer elapsed:
using System; using System.Linq; using cAlgo.API; using cAlgo.API.Indicators; using cAlgo.API.Internals; using cAlgo.Indicators; namespace cAlgo.Robots { [Robot(TimeZone = TimeZones.EasternStandardTime, AccessRights = AccessRights.None)] public class HighVolumeHours : Robot { private double _volume; protected override void OnStart() { // Here we set the initial volume to symbol minimum volume _volume = Symbol.VolumeInUnitsMin; // Here we start the timer and we set the interval to 4 hours Timer.Start(TimeSpan.FromHours(4)); } protected override void OnTimer() { // double the volume whenever OnTimer is called _volume *= 2; // Stop the timer if we reached the symbol maximum volume if (_volume >= Symbol.VolumeInUnitsMax) { _volume = Symbol.VolumeInUnitsMax; Timer.Stop(); } } } }
Hi,
You can do that by using position label to differentiate your cBot positions from other positions, then use Positions collection to count the number of your cBot open positions.
Then you can multiply the number of positions to volume or any other number you want to, for example if your cBot had 4 open positions you can multiply the volume by 2.
@amusleh
amusleh
25 Oct 2021, 09:45
Hi,
No, right now its not possible, you can't get your broker symbol categories from automate API.
You can open a thread on forum suggestions section for this feature.
If you want to categorize symbols by your self and then access the categories you can use watchlists from automate API.
@amusleh
amusleh
25 Oct 2021, 09:42
RE: RE: RE: RE:
yuval.ein said:
Hello
I have failed converting my code from a single to multi symbol. Perhaps you can attach a code sample of how you converted one of cTrader cBot samples (such as Sample Aligator, Sample Bears Power etc.) from single to multi symbol. An important note: The code must support running on a back test as well the same way (meaning one chart will run several symbols).
Thanks
Hi,
Here is the sample martingale cBot that works on two symbols, you must provide the symbol names:
using System;
using cAlgo.API;
using cAlgo.API.Internals;
namespace cAlgo
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class SampleMartingalecBot : Robot
{
[Parameter("Initial Quantity (Lots)", Group = "Volume", DefaultValue = 1, MinValue = 0.01, Step = 0.01)]
public double InitialQuantity { get; set; }
[Parameter("Stop Loss", Group = "Protection", DefaultValue = 40)]
public int StopLoss { get; set; }
[Parameter("Take Profit", Group = "Protection", DefaultValue = 40)]
public int TakeProfit { get; set; }
[Parameter("First Symbol", Group = "Symbols")]
public string FirstSymbolName { get; set; }
[Parameter("Second Symbol", Group = "Symbols")]
public string SecondSymbolName { get; set; }
private Random random = new Random();
protected override void OnStart()
{
Positions.Closed += OnPositionsClosed;
var firstSymbol = Symbols.GetSymbol(FirstSymbolName);
ExecuteOrder(InitialQuantity, firstSymbol, GetRandomTradeType());
var secondSymbol = Symbols.GetSymbol(SecondSymbolName);
ExecuteOrder(InitialQuantity, secondSymbol, GetRandomTradeType());
}
private void ExecuteOrder(double quantity, Symbol symbol, TradeType tradeType)
{
var volumeInUnits = symbol.QuantityToVolumeInUnits(quantity);
var result = ExecuteMarketOrder(tradeType, symbol.Name, volumeInUnits, "Martingale", StopLoss, TakeProfit);
if (result.Error == ErrorCode.NoMoney)
Stop();
}
private void OnPositionsClosed(PositionClosedEventArgs args)
{
Print("Closed");
var position = args.Position;
if (position.Label != "Martingale") return;
var symbol = Symbols.GetSymbol(args.Position.SymbolName);
if (position.GrossProfit > 0)
{
ExecuteOrder(InitialQuantity, symbol, GetRandomTradeType());
}
else
{
ExecuteOrder(position.Quantity * 2, symbol, position.TradeType);
}
}
private TradeType GetRandomTradeType()
{
return random.Next(2) == 0 ? TradeType.Buy : TradeType.Sell;
}
}
}
@amusleh
amusleh
01 Nov 2021, 08:26
Hi,
Please read this tutorial: How to Calculate Margin for Forex Trades (valutrades.com)
You have to convert the required margin from symbol base currency to your account currency.
For CFDs you can't get the base currency with automate API, that's the problem, but for Forex the base currency is the first currency on symbol pair.
@amusleh