示例#1
0
        /// <summary>
        /// Set the SL/TP on an existing position so that there's a chance it'll close in profit.
        /// Sets the SL to the wick limit of the latest and previous candle.
        /// This will only ever reduce the SL distance from it's current value.
        /// Set 'tp' to chance the current TP value as well (only if the SL is changed tho).
        /// Returns true if the SL was changed</summary>
        public bool CloseByStopLoss(Instrument instr, Position position, QuoteCurrency?tp = null)
        {
            // 'tp' is optional, it set it replaces the TP on 'position'
            Debug.Assert(instr.SymbolCode == position.SymbolCode);

            // Set the SL to just past the last candle
            var price = instr.CurrentPrice(-position.Sign());
            var sl    = position.Sign() > 0
                                ? Math.Min(instr[-1].WickLimit(-1), instr[0].WickLimit(-1)) - instr.Spread
                                : Math.Max(instr[-1].WickLimit(+1), instr[0].WickLimit(+1)) + instr.Spread;

            // Only make the SL smaller
            var sl_rel = position.Sign() * (position.EntryPrice - sl);

            if (sl_rel > position.StopLossRel())
            {
                return(false);
            }

            // Move the stop loss to just past the current price
            var trade = new Trade(instr, position)
            {
                SL = sl, TP = tp ?? position.TakeProfit
            };

            if (!ModifyOrder(position, trade))
            {
                ClosePosition(position, "CloseByStopLoss Failed");                 // Something went wrong, just close now
            }
            return(true);
        }
示例#2
0
        ///// <summary>Called when new data is received</summary>
        //public override void Step()
        //{
        //	var current_price = Instrument.CurrentPrice(0);
        //	var sym = Instrument.Symbol;

        //	// Find the stats for the recent price history
        //	PriceStats.Add((double)current_price);

        //	// Synchronise the Positions with our list
        //	SynchroniseLivePositions();

        //	// Measure the current net position
        //	var net = NetPosition;

        //	// If the sum of all trades is greater than the threshold, cash in
        //	// If the sum of all trades exceeds 90% of the balance to risk, bail out
        //	var profit_threshold = Misc.Max(1.0, Broker.Balance * TakeProfitPC);
        //	if (net > profit_threshold)
        //	{
        //		CloseOut();
        //		return; // Return so that closed positions get output while debugging
        //	}
        //	if (net < -BalanceRisked)
        //	{
        //		CloseOut();
        //		return; // Return so that closed positions get output while debugging
        //	}

        //	// Attempt to compress the positions
        //	for (;Positions.Count > 2;)
        //	{
        //		var pos0 = Positions.Back(0);
        //		var pos1 = Positions.Back(1);
        //		if (pos0.NetProfit + pos1.NetProfit > 1.0)
        //		{
        //			Broker.ClosePosition(pos0);
        //			Broker.ClosePosition(pos1);
        //			continue;
        //		}
        //		break;
        //	}

        //	// If we have no position, make a trade
        //	if (Positions.Count == 0)
        //	{
        //		// Get the current price direction
        //		var q = Quadratic.FromPoints(
        //			new v2(-2f, (float)Instrument[-2].Median),
        //			new v2(-1f, (float)Instrument[-1].Median),
        //			new v2(-0f, (float)Instrument[-0].Median));
        //		var next_price =(QuoteCurrency)q.F(1.0);

        //		var tt = next_price > current_price ? TradeType.Buy : TradeType.Sell;
        //		var sign = tt.Sign();

        //		// Create the initial trade
        //		var volume = sym.VolumeMin;
        //		var risk = Broker.MaxSL(Instrument, volume);
        //		var ep = Instrument.CurrentPrice(sign);
        //		var tp = ep + sign * risk;
        //		var sl = ep - sign * risk;
        //		var trade = new Trade(Instrument, tt, Label, ep, sl, tp, volume);

        //		// Record how much we're risking on this set of trades
        //		BalanceRisked = sym.QuoteToAcct(risk * volume);

        //		// Open the position
        //		var pos = Broker.CreateOrder(trade);
        //		if (pos != null)
        //			Positions.Add(pos);
        //	}
        //	else
        //	{
        //		// Get the loss threshold given the current number of trades
        //		var loss_per_level = BalanceRisked / ReversesCount;
        //		var loss_threshold = Positions.Count * loss_per_level;

        //		// If the net profit has dropped below the threshold, open a reverse trade
        //		if (net < -loss_threshold)
        //		{
        //			// The reverse trade is created such that the total risk remains the same.
        //			var prev = Positions.Back();
        //			var volume = sym.NormalizeVolume(prev.Volume * (Positions.Count + 1) / Positions.Count);
        //			var tt = prev.TradeType.Opposite();
        //			var ep = Instrument.CurrentPrice(tt.Sign());
        //			var tp = prev.StopLossAbs();
        //			var sl = prev.TakeProfitAbs();
        //			var trade = new Trade(Instrument, tt, Label, ep, sl, tp, volume);

        //			// Open the reverse position
        //			var pos = Broker.CreateOrder(trade);
        //			if (pos != null)
        //				Positions.Add(pos);
        //		}
        //	}

        //	int break_point;
        //	if (Instrument.NewCandle)
        //		break_point = 1;
        //}

        ///// <summary>Update the collection 'Positions' with any live positions created by this strategy</summary>
        //private void SynchroniseLivePositions()
        //{
        //	var live_positions = Bot.Positions.ToHashSet(x => x.Id);
        //	Positions.RemoveIf(x => !live_positions.Contains(x.Id));
        //}

        /// <summary>Returns a trade when a likely good trade is identified. Or null</summary>
        private Trade FindEntry()
        {
            // Get the current price direction
            var q = Quadratic.FromPoints(
                new v2(-2f, (float)Instrument[-2].Close),
                new v2(-1f, (float)Instrument[-1].Close),
                new v2(-0f, (float)Instrument[-0].Close));

            // Choose the trade type
            var curr_price = (double)Instrument.CurrentPrice(0);
            var next_price = q.F(1.0);
            var tt         = next_price > curr_price ? TradeType.Buy : TradeType.Sell;
            var sign       = tt.Sign();

            {                                                 // Look for some confirming signals
                // Does it match the long period EMA?
                const double ema100_threshold_gradient = 0.1; // pips per index
                var          ema100  = Bot.Indicators.ExponentialMovingAverage(Instrument.Data.Close, 100);
                var          grad100 = ema100.Result.FirstDerivative() / Instrument.MCS;
                if (Math.Abs(grad100) < ema100_threshold_gradient || Math.Sign(grad100) != sign)
                {
                    return(null);
                }

                // Does it match the short period EMA?
                const double ema14_threshold_gradient = 0.1f;                 // pips per index
                var          ema14  = Bot.Indicators.ExponentialMovingAverage(Instrument.Data.Close, 14);
                var          grad14 = ema14.Result.FirstDerivative() / Instrument.MCS;
                if (Math.Abs(grad14) < ema14_threshold_gradient || Math.Sign(grad14) != sign)
                {
                    return(null);
                }

                // Is the price within the MCS of the long period EMA?
                if (Math.Abs(curr_price - ema100.Result.LastValue) > Instrument.MCS)
                {
                    return(null);
                }

                // Is the instrument over-bought or over-sold
                var rsi = Bot.Indicators.RelativeStrengthIndex(Instrument.Data.Close, 14);
                if (tt == TradeType.Buy && rsi.Result.LastValue > 70.0)
                {
                    return(null);                    // Over bought
                }
                if (tt == TradeType.Sell && rsi.Result.LastValue < 30.0)
                {
                    return(null);                    // Over sold
                }
                // Has the current price just left a strong SnR level?

                // Is there a candle pattern that agrees with the trade
            }
            return(new Trade(Instrument, tt, Label));
        }
示例#3
0
        /// <summary>
        /// Create a trade with automatic SL and TP levels set.
        /// SL/TP levels are set based on the current account balance (even if 'idx' != 0)</summary>
        /// <param name="instr">The instrument to be traded</param>
        /// <param name="tt">Whether to buy or sell</param>
        /// <param name="label">Optional. An identifying name for the trade</param>
        /// <param name="ep">Optional. The price at which the trade was entered. (default is current ask/bid price)</param>
        /// <param name="sl">Optional. The stop loss (absolute) to use instead of automatically finding one</param>
        /// <param name="tp">Optional. The take profit (absolute) to use instead of automatically finding one</param>
        /// <param name="risk">Optional. Scaling factor for the amount to risk. (default is 1.0)</param>
        /// <param name="comment">Optional. A comment/tag associated with the trade</param>
        /// <param name="idx">Optional. The instrument index of when the trade was created. (default is the current time)</param>
        public Trade(Instrument instr, TradeType tt, string label = null, QuoteCurrency?ep = null, QuoteCurrency?sl = null, QuoteCurrency?tp = null, double?risk = null, string comment = null, Idx?idx = null, EResult result = EResult.Unknown)
            : this(instr, tt, label, 0, null, null, 0, comment : comment, idx : idx, result : result)
        {
            try
            {
                var bot   = instr.Bot;
                var sign  = tt.Sign();
                Idx index = idx ?? 0;
                bot.Debugging.Trace("Creating Trade (Index = {0})".Fmt(TradeIndex));

                // If the index == 0, add the fractional index amount
                if (index == 0)
                {
                    var ticks_elapsed    = bot.UtcNow.Ticks - instr.Latest.Timestamp;
                    var ticks_per_candle = instr.TimeFrame.ToTicks();
                    EntryIndex += Maths.Clamp((double)ticks_elapsed / ticks_per_candle, 0.0, 1.0);
                    ExitIndex   = EntryIndex;
                }

                // Set the trade entry price
                EP = ep ?? (index == 0
                                        ? (QuoteCurrency)instr.CurrentPrice(sign)                                   // Use the latest price
                                        : (QuoteCurrency)instr[index].Open + (sign > 0 ? instr.Symbol.Spread : 0)); // Use the open price of the candle at 'index'

                // Choose a risk scaler
                risk = risk ?? 1.0;

                // Find the account currency value of the available risk
                var balance_to_risk = bot.Broker.BalanceToRisk * risk.Value;
                if (balance_to_risk == 0)
                {
                    throw new Exception("Insufficient available risk. Current Risk: {0}%, Maximum Risk: {1}%".Fmt(100 * bot.Broker.TotalRiskFrac, 100.0 * bot.Settings.MaxRiskFrac));
                }

                // Require the SL to be at least 2 * the median candle size
                var volatility = instr.Symbol.QuoteToAcct(2 * instr.MCS * instr.Symbol.VolumeMin);
                if (balance_to_risk < volatility)
                {
                    throw new Exception("Insufficient available risk. Volatility: {0}, Balance To Risk: {1}".Fmt(volatility, balance_to_risk));
                }

                // Get the instrument to recommend trade exit conditions
                var exit = instr.ChooseTradeExit(tt, EP, idx: index, risk: risk);
                TP     = tp != null ? tp.Value : exit.TP;
                SL     = sl != null ? sl.Value : exit.SL;
                Volume = sl != null?instr.Bot.Broker.ChooseVolume(instr, sl.Value / risk.Value) : exit.Volume;
            }
            catch (Exception ex)
            {
                Error = ex;
            }
        }
示例#4
0
        /// <summary></summary>
        protected override void StepCore()
        {
            if (!Instrument.NewCandle)
            {
                return;
            }

            // Don't adjust the SL until the profit is better than MinRtR
            if (!MinRtRExceeded)
            {
                return;
            }

            // Look at the last few candles to find the level for the SL
            var range = Instrument.PriceRange(-NumCandles, 1);

            // Don't set the SL above the current price
            var sign   = Position.Sign();
            var min_sl = Instrument.CurrentPrice(-sign) - sign * Instrument.MCS;

            // Choose the worst over the range and adjust the SL
            if (Position.Sign() > 0)
            {
                var sl = range.Beg - 5 * Instrument.PipSize - Instrument.Spread;
                if (sl < min_sl && (sl > Position.StopLoss || Position.StopLoss == null))
                {
                    Broker.ModifyOrder(Instrument, Position, sl: sl);
                }
            }
            else
            {
                var sl = range.End + 5 * Instrument.PipSize + Instrument.Spread;
                if (sl > min_sl && (sl < Position.StopLoss || Position.StopLoss == null))
                {
                    Broker.ModifyOrder(Instrument, Position, sl: sl);
                }
            }
        }
        /// <summary>Called when new data is received</summary>
        public override void Step()
        {
            base.Step();
            if (Instrument.NewCandle)
            {
                Dump();
            }

            var mcs             = Instrument.MCS;
            var price           = Instrument.LatestPrice;
            var trend_sign_slow = TrendSignSlow;
            var trend_sign_fast = TrendSignFast;

            // On a significantly extreme price level, buy/sell
            // For opening positions, use Bid when the price is high, Ask when the price is low.
            var sign = -ProbSign;
            var prob = Prob(sign);

            if (Math.Abs(prob) > OpenPositionProb)
            {
                // Todo:
                // The TrendSignFast is preventing trades being taken
                // If this worked it would offset the bad trades at MA crosses
                Dump();

                // Buy the lows, Sell the highs
                var ep   = Instrument.CurrentPrice(sign);
                var risk = Risk / 2;                 // Divide the risk amongst the number of positions that can be opened (1 in each direction)
                Debugging.Trace("Entry Trigger - {0} - prob={1:N3}".Fmt(sign > 0 ? "Buy" : "Sell", prob));
                Debugging.Trace(" FastTrend = {0}, SlowTrend = {1}".Fmt(trend_sign_fast, trend_sign_slow));

                for (;;)
                {
                    // Only allow one trade in each direction using this method
                    if (Positions.Count(x => x.Sign() == sign) != 0)
                    {
                        Debugging.Trace("  -Position with this sign already exists");
                        break;
                    }
                    Debugging.Trace("  +No existing {0} position".Fmt(sign));

                    // Only open positions in the direction of the trend
                    if (sign == -trend_sign_fast)
                    {
                        Debugging.Trace("  -Against the trend ({0})".Fmt(trend_sign_fast));
                        break;
                    }
                    Debugging.Trace("  +Not against the trend ({0} vs. {1})".Fmt(sign, trend_sign_fast));

                    // Don't open positions too close together
                    if (Broker.NearbyPositions(Label, ep, Instrument.MCS * MinTradeSeparation, sign))
                    {
                        Debugging.Trace("  -Nearby trades with the same sign ({0})".Fmt(sign));
                        break;
                    }
                    Debugging.Trace("  +No nearby trades with the same sign ({0})".Fmt(sign));

                    // Only open positions when the recent price has been heading in the direction we want to trade
                    var price_trend = Instrument.HighRes.FirstDerivative(-1) / Instrument.PipSize;
                    if (Math.Sign(price_trend) == -sign)
                    {
                        Debugging.Trace("  -Price trend ({0:N3}) against trade sign ({1})".Fmt(price_trend, sign));
                        break;
                    }
                    Debugging.Trace("  +Price trend ({0:N3} pips/tick) matches trade sign ({1})".Fmt(price_trend, sign));

                    // Don't open a position if the MA's look like they're about to cross
                    // in a direction that would make the trade against the trend.
                    var next_cross_idx = NextCrossIndex;
                    var ma_cross_sign  = MA0[0].CompareTo(MA1[0]);
                    if (next_cross_idx != null && next_cross_idx.Value < 2.5 && ma_cross_sign == sign)
                    {
                        Debugging.Trace("  -MA cross predicted in {0:N3} candles".Fmt(next_cross_idx.Value));
                        break;
                    }
                    Debugging.Trace("  +No MA cross from {0} to {1} predicted soon ({2})".Fmt(ma_cross_sign, -ma_cross_sign, next_cross_idx != null ? ((double)next_cross_idx.Value).ToString("N3") : ">5"));

                    // Choose a SL based on SnR levels and the slow MA
                    var rel = Math.Abs(ep - MA1[0]) + mcs;

                    // Create the positions
                    var tt    = CAlgo.SignToTradeType(sign);
                    var sl    = ep - sign * rel;
                    var tp    = ep + sign * rel * 1.5;
                    var vol   = Broker.ChooseVolume(Instrument, rel, risk: risk);
                    var trade = new Trade(Instrument, tt, Label, ep, sl, tp, vol, result: Trade.EResult.Open);
                    //Debugging.LogTrade(trade);
                    Broker.CreateOrder(trade);
                    break;
                }
            }
        }
示例#6
0
        /// <summary>Set the SL or TP for a position such that it will close when the price hits 'price'</summary>
        public void CloseAt(Instrument instr, Position position, QuoteCurrency price)
        {
            Debug.Assert(instr.SymbolCode == position.SymbolCode);
            Bot.TradeStats.Event(position, "CloseAt");

            var trade = (Trade)null;

            if (position.TradeType == TradeType.Buy)
            {
                // If the current price is not between 'price' and 'position.StopLoss' move the SL to 'price'
                if (!instr.CurrentPrice(-1).Within(position.StopLoss ?? -double.MaxValue, price))
                {
                    trade = new Trade(instr, position)
                    {
                        SL = price - instr.Spread
                    }
                }
                ;

                // If the current price is not between 'price' and 'position.TakeProfit' move the TP to 'price'
                else if (!instr.CurrentPrice(+1).Within(price, position.TakeProfit ?? +double.MaxValue))
                {
                    trade = new Trade(instr, position)
                    {
                        TP = price
                    }
                }
                ;

                // If the current price spans 'price' close immediately
                else
                {
                    trade = null;
                }
            }
            else
            {
                // If the current price is not between 'price' and 'position.StopLoss' move the SL to 'price'
                if (!instr.CurrentPrice(+1).Within(price, position.StopLoss ?? +double.MaxValue))
                {
                    trade = new Trade(instr, position)
                    {
                        SL = price + instr.Spread
                    }
                }
                ;

                // If the current price is not between 'price' and 'position.TakeProfit' move the TP to 'price'
                else if (!instr.CurrentPrice(-1).Within(position.TakeProfit ?? -double.MaxValue, price))
                {
                    trade = new Trade(instr, position)
                    {
                        TP = price
                    }
                }
                ;

                // If the current price spans 'price' close immediately
                else
                {
                    trade = null;
                }
            }

            // Update or close the trade
            if (trade != null)
            {
                // Move the SL or TP
                ModifyOrder(position, trade);
            }
            else
            {
                // Close immediately if the price spread spans 'price'
                ClosePosition(position, "CloseAt at current Price");
            }
        }
示例#7
0
        /// <summary>Manage an open trade. This should be called on each tick</summary>
        protected override void StepCore()
        {
            // Move SL to break even when profit > BreakEvenThreshold (adjusted for Spread)
            var adjusted_profit = Position.NetProfit - Instrument.Symbol.QuoteToAcct(Instrument.Spread * Position.Volume);

            if (adjusted_profit > BreakEvenThreshold && Position.StopLossRel() > 0)
            {
                Bot.Debugging.Trace("Moving SL to break even - Profit ${0} > Threshold ${1}".Fmt(Position.NetProfit, BreakEvenThreshold));

                var trade = new Trade(Instrument, Position)
                {
                    SL = Position.EntryPrice + Position.Sign() * 2.0 * Instrument.Spread
                };
                Broker.ModifyOrder(Position, trade);
            }

            // What about candle follow mode:
            // If the price is heading for the TP and the last tops/bottoms of the last few candles
            // have been steadily increasing/decreasing. Move the SL to just above/below the previous candle

            // A state machine for managing the position
            switch (State)
            {
            // In this state, the trade looks good. Keep it open.
            case EState.TradeLooksGood:
                #region
            {
                // Enter scalp mode when profit > scalp threshold
                if (Profit > ScalpThreshold)
                {
                    Bot.Debugging.Trace("Entering scalp mode - Profit ${0} > Threshold ${1}".Fmt(Profit, ScalpThreshold));
                    State = EState.Scalp;
                }
                else if (CandlesSincePeak >= ColdFeetCount)
                {
                    // It's been a while since a profit peak was set...
                    Bot.Debugging.Trace("Getting nervous... no peaks for a while");
                    State = EState.LookForExitAfterNextPeak;
                }
                break;
            }

                #endregion
            case EState.Scalp:
            {
                // In this mode we've made a decent profit.
                var close = false;
                for (;;)
                {
                    //// Close if the profit drops to fraction of the peak
                    //const double ScalpFraction = 0.5;
                    //if (Position.NetProfit < ScalpFraction * PeakProfit)
                    //{
                    //	close = true;
                    //	Debugging.Trace("Position closed - profit dropped by {0} - ${1}".Fmt(ScalpFraction, Position.NetProfit));
                    //}

                    // Close if the closed candle is an indecision candle.
                    if (Instrument.NewCandle &&
                        Instrument[-1].Type(Instrument.MCS).IsIndecision())
                    {
                        Bot.Debugging.Trace("Closing position - indecision candle");
                        close = true;
                        break;
                    }

                    // Close if the peak of the candle just closed is not better than the candle before's peak i.e. Not higher lows, or lower highs
                    if (Instrument.NewCandle &&
                        Position.EntryTime < Instrument[-1].TimestampUTC &&
                        Instrument.SequentialPeaks(Position.Sign(), 0) < 1)
                    {
                        Bot.Debugging.Trace("Closing position - peaks oppose trend direction");
                        close = true;
                        break;
                    }

                    // Close if the candle closes worse then the close of the -2 candle
                    if (Instrument.NewCandle &&
                        Position.EntryTime < Instrument[-1].TimestampUTC &&
                        Math.Sign(Instrument[-1].Close - Instrument[-2].Close) != Position.Sign())
                    {
                        Bot.Debugging.Trace("Closing position - candle close was worse that close of -2 candle");
                        close = true;
                        break;
                    }

                    // Close if the profit is huge
                    if (Position.NetProfit > 2.0 * ScalpThreshold && TicksSincePeak > 10)
                    {
                        Bot.Debugging.Trace("Closing position - huge spike detected!");
                        close = true;
                        break;
                    }

                    // Don't close.
                    break;
                }
                if (close)
                {
                    Broker.ClosePosition(Position, "{0} - Scalp".Fmt(R <PositionManagerNervious> .NameOf));
                    State = EState.PositionClosed;
                }
                break;
            }

            case EState.TrailingSL:
            {
                // In this mode, we move the SL up to just above/below a recently closed candle
                if (Instrument.NewCandle)
                {
                    var sign  = Position.TradeType.Sign();
                    var limit = Instrument.CurrentPrice(-sign);
                    foreach (var c in Instrument.CandleRange(-3, 0))
                    {
                        limit = sign > 0 ? Math.Min(limit, c.Low) : Math.Max(limit, c.High);
                    }

                    // Move the SL if in the correct direction
                    if (sign > 0 && limit > Position.StopLoss ||
                        sign < 0 && limit < Position.StopLoss)
                    {
                        var trade = new Trade(Instrument, Position)
                        {
                            SL = limit
                        };
                        Broker.ModifyOrder(Position, trade);
                    }
                }
                break;
            }

            case EState.LookForExitAfterNextPeak:
            {
                // In this state, the profit hit a peak a while ago,
                // and we're waiting for it to come back to that peak
                // level so we can bail out.
                if (NewPeak)
                {
                    State = EState.CloseAtNextNonPeak;
                    Bot.Debugging.Trace("Closing at next non peak");
                }
                else if (CandlesSincePeak >= 2 * ColdFeetCount)
                {
                    State = EState.BailIfProfitable;
                    Bot.Debugging.Trace("Closing when profitable");
                }
                break;
            }

            case EState.CloseAtNextNonPeak:
            {
                // In this state we're looking to exit the trade the
                // next time the profit peak is not set
                if (!NewPeak)
                {
                    Broker.ClosePosition(Position, "{0} - Non-Peak".Fmt(R <PositionManagerNervious> .NameOf));
                    State = EState.PositionClosed;
                    Bot.Debugging.Trace("Position closed - non-peak");
                }
                break;
            }

            case EState.CloseAtNextProfitDrop:
            {
                // In this state we just want out with the minimum of loss.
                // Bail as soon as the profit decreases
                if (!IsGain)
                {
                    Broker.ClosePosition(Position, "{0} - Next Profit Drop".Fmt(R <PositionManagerNervious> .NameOf));
                    State = EState.PositionClosed;
                    Bot.Debugging.Trace("Position closed - profit dropped");
                }
                break;
            }

            case EState.BailIfProfitable:
            {
                // In this state, it's been too long since the peak was last
                // hit, bail out if profitable
                if (NewPeak)
                {
                    State = EState.CloseAtNextNonPeak;
                }
                else if (Position.NetProfit > 0)
                {
                    Broker.ClosePosition(Position, "{0} - Bail With Profit".Fmt(R <PositionManagerNervious> .NameOf));
                    State = EState.PositionClosed;
                }
                else if (CandlesSinceProfitable > 4 * ColdFeetCount)
                {
                    State = EState.CloseAtNextProfitDrop;
                    Bot.Debugging.Trace("Closing at next drop in profit");
                }
                break;
            }
            }
        }
示例#8
0
        /// <summary>Called when new data is received</summary>
        public override void Step()
        {
            base.Step();
            if (Instrument.NewCandle)
            {
                Dump();
            }

            // Don't open new positions while there are pending orders or existing positions
            if (Positions.Any() || PendingOrders.Any())
            {
                return;
            }

            // Look for peak patterns
            TradeType     tt;
            QuoteCurrency ep;
            var           pat = Instrument.IsPeakPattern(Instrument.IdxNow, out tt, out ep);

            if (pat != null)
            {
                var pattern = pat.Value;

                Dump();
                Debugging.Dump(new PricePeaks(Instrument, 0));
                Debugging.Dump(new SnR(Instrument));
                Debugging.Trace("Peak pattern: {0}".Fmt(pattern));

                var sign = tt.Sign();
                var mcs  = Instrument.MCS;

                // Convert the patterns to trades
                switch (pattern)
                {
                case EPeakPattern.BreakOutHigh:
                case EPeakPattern.BreakOutLow:
                {
                    // For break outs, enter immediately and use a candle
                    // follow position manager because they tend to run.
                    var price_range = Instrument.PriceRange(-10, 1);
                    var sl          = price_range.Mid - sign * price_range.Size * 0.6;
                    var tp          = (QuoteCurrency?)null;
                    var vol         = Broker.ChooseVolume(Instrument, Math.Abs(ep - sl), risk: Risk);
                    var trade       = new Trade(Instrument, tt, Label, ep, sl, tp, vol);
                    var pos         = Broker.CreateOrder(trade);
                    if (pos != null)
                    {
                        PositionManagers.Add(new PositionManagerCandleFollow(this, pos, 5));
                    }

                    break;
                }

                case EPeakPattern.HighReversal:
                case EPeakPattern.LowReversal:
                {
                    // For reversals, enter when the price is near the trend line.
                    // Use a fixed SL/TP
                    var price_range = Instrument.PriceRange(-10, 1);
                    var sl          = price_range.Mid - sign * price_range.Size * 0.6;
                    var tp          = price_range.Mid + sign * price_range.Size * 0.4;
                    var vol         = Broker.ChooseVolume(Instrument, Math.Abs(ep - sl), risk: Risk);

                    // If the current price is better than the entry price, enter immediately
                    if (sign * (ep - Instrument.CurrentPrice(sign)) > 0)
                    {
                        var trade = new Trade(Instrument, tt, Label, ep, sl, tp, vol);
                        Broker.CreateOrder(trade);
                    }
                    else
                    {
                        var order = new Trade(Instrument, tt, Label, ep, sl, tp, vol)
                        {
                            Expiration = Instrument.ExpirationTime(1)
                        };
                        Broker.CreatePendingOrder(order);
                    }
                    break;
                }
                }
            }
        }
示例#9
0
        /// <summary>Called when new data is received</summary>
        public override void Step()
        {
            base.Step();

            // Find the position associated with this strategy
            Position = FindLivePosition(Position);

            switch (State)
            {
            case EState.FindEntryTrigger:
                #region
            {
                // In this state we're waiting for an entry trigger.
                Debug.Assert(Position == null);

                // Do nothing unless the conditions are right
                if (SuitabilityScore < 0.5)
                {
                    return;
                }

                if (Instrument.NewCandle)
                {
                    Dump();
                }

                // Always trade with the trend
                var sign = Math.Sign(Trend);
                var tt   = sign > 0 ? TradeType.Buy : TradeType.Sell;

                // Look for a candle pattern that indicates entry
                int           forecast_direction;
                QuoteCurrency target_entry;
                if (!Instrument.IsCandlePattern(0, out forecast_direction, out target_entry) ||
                    forecast_direction != sign)
                {
                    return;
                }

                // Switch to the 'EnterOnPullBack' state
                State       = EState.EnterOnPullBack;
                TargetEntry = new TargetEntryData(target_entry, tt);
                Dump();
                break;
            }

                #endregion
            case EState.EnterOnPullBack:
                #region
            {
                if (Instrument.NewCandle)
                {
                    Dump();
                }

                // In this state we're waiting for the price to pull back
                // to the target entry. Check this on every tick.
                var tt = TargetEntry.TT;
                var cp = Instrument.CurrentPrice(tt.Sign());
                if (Misc.Sign(cp - TargetEntry.Price) != tt.Sign())
                {
                    var trade = new Trade(Bot, Instrument, tt, Label);
                    Position = Bot.Broker.CreateOrder(trade);
                    Dump();
                }
                break;
            }

                #endregion
            case EState.ManagePosition:
                #region
            {
                if (Instrument.NewCandle)
                {
                    Dump();
                }

                // Manage a trade position
                PositionManager.Step();
                break;
            }
                #endregion
            }
        }