modify them

Created at 15 Mar 2024, 14:26
How’s your experience with the cTrader Platform?
Your feedback is crucial to cTrader's development. Please take a few seconds to share your opinion and help us improve your trading experience. Thanks!
YW

yw198914

Joined 15.03.2024

modify them
15 Mar 2024, 14:26


using System;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;

namespace cAlgo
{
    public static class Extensions
    {
        public static TradeType Opposite(this TradeType tradeType)
        {
            return tradeType == TradeType.Buy ? TradeType.Sell : TradeType.Buy;
        }
    }

    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class DualMovingAverageStrategy : Robot
    {
        [Parameter("Fast Periods", DefaultValue = 5)]
        public int FastPeriods { get; set; }

        [Parameter("Slow Periods", DefaultValue = 20)]
        public int SlowPeriods { get; set; }

        [Parameter("Quantity (Lots)", Group = "Volume", DefaultValue = 1, MinValue = 0.01, Step = 0.01)]
        public double Quantity { get; set; }

        [Parameter("Target Profits (%)", Group = "Volume", DefaultValue = 5, MinValue = 0.01, Step = 0.01)]
        public double TargetProfits { get; set; }

        private MovingAverage _fastMA;
        private MovingAverage _slowMA;

        private double _initialBalance;
        private bool _shouldOpenLongNextBar;
        private bool _shouldOpenShortNextBar;
        private int _lastBuySignalBarIndex;
        private int _lastSellSignalBarIndex;
        private const double PriceOffsetForPendingOrder = 10; // 示例:设置一个固定的挂单价格偏差

        protected override void OnStart()
        {
            _initialBalance = Account.Balance;
            _fastMA = Indicators.MovingAverage(Bars.ClosePrices, FastPeriods, MovingAverageType.Simple);
            _slowMA = Indicators.MovingAverage(Bars.ClosePrices, SlowPeriods, MovingAverageType.Simple);
        }

        protected override void OnBar()
        {
            var profit = Account.Balance - _initialBalance;

            if (profit > 0 && ((profit / _initialBalance) * 100) > TargetProfits)
            {
                CloseAllPositions();
            }

            // 当发生金叉时
            if (_fastMA.Result.LastValue > _slowMA.Result.LastValue && _fastMA.Result[_fastMA.Result.Count - 2] <= _slowMA.Result[_fastMA.Result.Count - 3] && !_shouldOpenLongNextBar)
            {
                _shouldOpenLongNextBar = true;
                _lastBuySignalBarIndex = Bars.Count - 1;
                CloseShortPositions();

                // 创建挂单,基于当前Bar的高点加一个固定的价格偏差
                double buyPrice = Bars.HighPrices[Bars.Count - 1] + PriceOffsetForPendingOrder * Symbol.PipSize;
                var buyOrderTicket = ExecutePendingOrder(TradeType.Buy, Symbol, buyPrice, Symbol.QuantityToVolumeInUnits(Quantity), "Buy with Offset");
                if (!buyOrderTicket.IsFilled)
                {
                    Print($"Error creating pending buy order: {buyOrderTicket.Error?.Message}");
                }
            }
            // 当发生死叉时
            else if (_fastMA.Result.LastValue < _slowMA.Result.LastValue && _fastMA.Result[_fastMA.Result.Count - 2] >= _slowMA.Result[_fastMA.Result.Count - 3] && !_shouldOpenShortNextBar)
            {
                _shouldOpenShortNextBar = true;
                _lastSellSignalBarIndex = Bars.Count - 1;
                CloseLongPositions();

                // 创建挂单,基于当前Bar的低点减一个固定的价格偏差
                double sellPrice = Bars.LowPrices[Bars.Count - 1] - PriceOffsetForPendingOrder * Symbol.PipSize;
                var sellOrderTicket = ExecutePendingOrder(TradeType.Sell, Symbol, sellPrice, Symbol.QuantityToVolumeInUnits(Quantity), "Sell with Offset");
                if (!sellOrderTicket.IsFilled)
                {
                    Print($"Error creating pending sell order: {sellOrderTicket.Error?.Message}");
                }
            }

            // 检查并取消未触发的旧挂单(此处假设挂单有效时间为1分钟,仅作演示)
            CancelOldPendingOrders(TimeSpan.FromMinutes(1));
        }

        private void CloseLongPositions()
        {
            foreach (var position in Positions)
            {
                if (position.TradeType == TradeType.Buy)
                {
                    ClosePosition(position);
                }
            }
        }

        private void CloseShortPositions()
        {
            foreach (var position in Positions)
            {
                if (position.TradeType == TradeType.Sell)
                {
                    ClosePosition(position);
                }
            }
        }

        private void CloseAllPositions()
        {
            CloseLongPositions();
            CloseShortPositions();
        }

        private void ClosePosition(Position position)
        {
            if (position != null && position.TradeType != TradeType.None)
            {
                var oppositeTradeType = position.TradeType.Opposite();
                var closeOrderTicket = ExecuteMarketOrder(oppositeTradeType, position.Symbol, position.Volume, "Closing Position");
                if (!closeOrderTicket.IsFilled)
                {
                    Print($"Error closing position: {closeOrderTicket.Error?.Message}");
                }
            }
        }

        // 执行挂单请求
        private OrderTicket ExecutePendingOrder(TradeType tradeType, Symbol symbol, double price, double volume, string comment)
        {
            var limitOrderRequest = new LimitOrderRequest(tradeType, symbol, price, volume, comment);
            return ExecuteOrderAsync(limitOrderRequest).Result;
        }

        // 取消旧的挂单
        private void CancelOldPendingOrders(TimeSpan ageThreshold)
        {
            foreach (var order in PendingOrders)
            {
                if (order.CreateTimeUtc.Add(ageThreshold) < Server.Time)
                {
                    order.Cancel();
                }
            }
        }
    }
}


@yw198914