牛熊策略升级版[gekko]

本人非原创,原文链接https://justhodl.blogspot.com/2018/02/gekko-rsibullbear-tradingview.html

RSI_BULL_BEAR是由@ tommiehansen所撰写的Gekko交易策略,除了最原版的之外,现在最被讨论的大概就是加上ADX指标调整的RSI_BULL_BEAR_ADX了,ADX可以确认市场是否存在趋势以及衡量其强度,只要搭配好的参数很容易能超出原版的表现,在对不同币种的适应性下也更好,但现在又有由 @ Kohette 再加入了Ping Pong trading的概念,简单的说就是在买入后会马上挂一个高于原价%数的卖单,赚取短线的反弹,卖出时反之亦然。

每个策略配置两个文件 *.js 和 *.toml。 配置路径分别为 gekko/strategies 和 gekko/config/strategies


RSI_BULL_BEAR

RSI_BULL_BEAR.js

/*
    RSI Bull and Bear
    Use different RSI-strategies depending on a longer trend
    3 feb 2017
    
    (CC-BY-SA 4.0) Tommie Hansen
    https://creativecommons.org/licenses/by-sa/4.0/
    
*/

// req's
var log = require ('../core/log.js');
var config = require ('../core/util.js').getConfig();

// strategy
var strat = {
    
    /* INIT */
    init: function()
    {
        this.name = 'RSI Bull and Bear';
        this.requiredHistory = config.tradingAdvisor.historySize;
        this.resetTrend();      
        
        // debug? set to flase to disable all logging/messages (improves performance)
        this.debug = false;
        
        // performance
        config.backtest.batchSize = 1000; // increase performance
        config.silent = true;
        config.debug = false;
        
        // add indicators
        this.addTulipIndicator('maSlow', 'sma', { optInTimePeriod: this.settings.SMA_long });
        this.addTulipIndicator('maFast', 'sma', { optInTimePeriod: this.settings.SMA_short });
        this.addTulipIndicator('BULL_RSI', 'rsi', { optInTimePeriod: this.settings.BULL_RSI });
        this.addTulipIndicator('BEAR_RSI', 'rsi', { optInTimePeriod: this.settings.BEAR_RSI });
        
        // debug stuff
        this.startTime = new Date();
        this.stat = {
            bear: { min: 100, max: 0 },
            bull: { min: 100, max: 0 }
        };
        
    }, // init()
    
    
    /* RESET TREND */
    resetTrend: function()
    {
        var trend = {
            duration: 0,
            direction: 'none',
            longPos: false,
        };
    
        this.trend = trend;
    },
    
    /* get lowest/highest for backtest-period */
    lowHigh: function( rsi, type )
    {
        let cur;
        if( type == 'bear' ) {
            cur = this.stat.bear;
            if( rsi < cur.min ) this.stat.bear.min = rsi; // set new
            if( rsi > cur.max ) this.stat.bear.max = rsi;
        }
        else {
            cur = this.stat.bull;
            if( rsi < cur.min ) this.stat.bull.min = rsi; // set new
            if( rsi > cur.max ) this.stat.bull.max = rsi;
        }
    },
    
    
    /* CHECK */
    check: function()
    {
        
        // get all indicators
        let ind = this.tulipIndicators,
            maSlow = ind.maSlow.result.result,
            maFast = ind.maFast.result.result,
            rsi;
            
        // BEAR TREND
        if( maFast < maSlow )
        {
            rsi = ind.BEAR_RSI.result.result;
            if( rsi > this.settings.BEAR_RSI_high ) this.short();
            else if( rsi < this.settings.BEAR_RSI_low ) this.long();
            
            if(this.debug) this.lowHigh( rsi, 'bear' );
            //log.debug('BEAR-trend');
        }

        // BULL TREND
        else
        {
            rsi = ind.BULL_RSI.result.result;
            if( rsi > this.settings.BULL_RSI_high ) this.short();
            else if( rsi < this.settings.BULL_RSI_low )  this.long();
            if(this.debug) this.lowHigh( rsi, 'bull' );
            //log.debug('BULL-trend');
        }
    
    }, // check()
    
    
    /* LONG */
    long: function()
    {
        if( this.trend.direction !== 'up' ) // new trend? (only act on new trends)
        {
            this.resetTrend();
            this.trend.direction = 'up';
            this.advice('long');
            //log.debug('go long');
        }
        
        if(this.debug)
        {
            this.trend.duration++;
            log.debug ('Long since', this.trend.duration, 'candle(s)');
        }
    },
    
    
    /* SHORT */
    short: function()
    {
        // new trend? (else do things)
        if( this.trend.direction !== 'down' )
        {
            this.resetTrend();
            this.trend.direction = 'down';
            this.advice('short');
        }
        
        if(this.debug)
        {
            this.trend.duration++;
            log.debug ('Short since', this.trend.duration, 'candle(s)');
        }
    },
    
    
    /* END backtest */
    end: function(){
        
        let seconds = ((new Date()- this.startTime)/1000),
            minutes = seconds/60,
            str;
            
        minutes < 1 ? str = seconds + ' seconds' : str = minutes + ' minutes';
        
        log.debug('====================================');
        log.debug('Finished in ' + str);
        log.debug('====================================');
        
        if(this.debug)
        {
            let stat = this.stat;
            log.debug('RSI low/high for period');
            log.debug('BEAR low/high: ' + stat.bear.min + ' / ' + stat.bear.max);
            log.debug('BULL low/high: ' + stat.bull.min + ' / ' + stat.bull.max);
        }

    }
    
};

module.exports = strat;

RSI_BULL_BEAR.toml

# SMA Trends
SMA_long = 1000
SMA_short = 50

# BULL
BULL_RSI = 10
BULL_RSI_high = 80
BULL_RSI_low = 60

# BEAR
BEAR_RSI = 15
BEAR_RSI_high = 50
BEAR_RSI_low = 20

# BULL/BEAR is defined by the longer SMA trends
# if SHORT over LONG = BULL
# if SHORT under LONG = BEAR

RSI_BULL_BEAR_ADX

RSI_BULL_BEAR_ADX.js

/*
    RSI Bull and Bear + ADX modifier
    1. Use different RSI-strategies depending on a longer trend
    2. But modify this slighly if shorter BULL/BEAR is detected
    -
    (CC-BY-SA 4.0) Tommie Hansen
    https://creativecommons.org/licenses/by-sa/4.0/
*/

// req's
var log = require('../core/log.js');
var config = require('../core/util.js').getConfig();

// strategy
var strat = {
    
    /* INIT */
    init: function()
    {
        // core
        this.name = 'RSI Bull and Bear + ADX';
        this.requiredHistory = config.tradingAdvisor.historySize;
        this.resetTrend();
        
        // debug? set to false to disable all logging/messages/stats (improves performance in backtests)
        this.debug = false;
        
        // performance
        config.backtest.batchSize = 1000; // increase performance
        config.silent = true;
        config.debug = false;
        
        // SMA
        this.addTulipIndicator('maSlow', 'sma', { optInTimePeriod: this.settings.SMA_long });
        this.addTulipIndicator('maFast', 'sma', { optInTimePeriod: this.settings.SMA_short });
        
        // RSI
        this.addTulipIndicator('BULL_RSI', 'rsi', { optInTimePeriod: this.settings.BULL_RSI });
        this.addTulipIndicator('BEAR_RSI', 'rsi', { optInTimePeriod: this.settings.BEAR_RSI });
        
        // ADX
        this.addTulipIndicator('ADX', 'adx', { optInTimePeriod: this.settings.ADX })
        
        // MOD (RSI modifiers)
        this.BULL_MOD_high = this.settings.BULL_MOD_high;
        this.BULL_MOD_low = this.settings.BULL_MOD_low;
        this.BEAR_MOD_high = this.settings.BEAR_MOD_high;
        this.BEAR_MOD_low = this.settings.BEAR_MOD_low;
        
        
        // debug stuff
        this.startTime = new Date();
        
        // add min/max if debug
        if( this.debug ){
            this.stat = {
                adx: { min: 1000, max: 0 },
                bear: { min: 1000, max: 0 },
                bull: { min: 1000, max: 0 }
            };
        }
        
        /* MESSAGES */
        
        // message the user about required history
        log.info("====================================");
        log.info('Running', this.name);
        log.info('====================================');
        log.info("Make sure your warmup period matches SMA_long and that Gekko downloads data if needed");
        
        // warn users
        if( this.requiredHistory < this.settings.SMA_long )
        {
            log.warn("*** WARNING *** Your Warmup period is lower then SMA_long. If Gekko does not download data automatically when running LIVE the strategy will default to BEAR-mode until it has enough data.");
        }
        
    }, // init()
    
    
    /* RESET TREND */
    resetTrend: function()
    {
        var trend = {
            duration: 0,
            direction: 'none',
            longPos: false,
        };
    
        this.trend = trend;
    },
    
    
    /* get low/high for backtest-period */
    lowHigh: function( val, type )
    {
        let cur;
        if( type == 'bear' ) {
            cur = this.stat.bear;
            if( val < cur.min ) this.stat.bear.min = val; // set new
            else if( val > cur.max ) this.stat.bear.max = val;
        }
        else if( type == 'bull' ) {
            cur = this.stat.bull;
            if( val < cur.min ) this.stat.bull.min = val; // set new
            else if( val > cur.max ) this.stat.bull.max = val;
        }
        else {
            cur = this.stat.adx;
            if( val < cur.min ) this.stat.adx.min = val; // set new
            else if( val > cur.max ) this.stat.adx.max = val;
        }
    },
    
    
    /* CHECK */
    check: function()
    {
        // get all indicators
        let ind = this.tulipIndicators,
            maSlow = ind.maSlow.result.result,
            maFast = ind.maFast.result.result,
            rsi,
            adx = ind.ADX.result.result;
        
            
        // BEAR TREND
        if( maFast < maSlow )
        {
            rsi = ind.BEAR_RSI.result.result;
            let rsi_hi = this.settings.BEAR_RSI_high,
                rsi_low = this.settings.BEAR_RSI_low;
            
            // ADX trend strength?
            if( adx > this.settings.ADX_high ) rsi_hi = rsi_hi + this.BEAR_MOD_high;
            else if( adx < this.settings.ADX_low ) rsi_low = rsi_low + this.BEAR_MOD_low;
                
            if( rsi > rsi_hi ) this.short();
            else if( rsi < rsi_low ) this.long();
            
            if(this.debug) this.lowHigh( rsi, 'bear' );
        }

        // BULL TREND
        else
        {
            rsi = ind.BULL_RSI.result.result;
            let rsi_hi = this.settings.BULL_RSI_high,
                rsi_low = this.settings.BULL_RSI_low;
            
            // ADX trend strength?
            if( adx > this.settings.ADX_high ) rsi_hi = rsi_hi + this.BULL_MOD_high;        
            else if( adx < this.settings.ADX_low ) rsi_low = rsi_low + this.BULL_MOD_low;
                
            if( rsi > rsi_hi ) this.short();
            else if( rsi < rsi_low )  this.long();
            if(this.debug) this.lowHigh( rsi, 'bull' );
        }
        
        // add adx low/high if debug
        if( this.debug ) this.lowHigh( adx, 'adx');
    
    }, // check()
    
    
    /* LONG */
    long: function()
    {
        if( this.trend.direction !== 'up' ) // new trend? (only act on new trends)
        {
            this.resetTrend();
            this.trend.direction = 'up';
            this.advice('long');
            if( this.debug ) log.info('Going long');
        }
        
        if( this.debug )
        {
            this.trend.duration++;
            log.info('Long since', this.trend.duration, 'candle(s)');
        }
    },
    
    
    /* SHORT */
    short: function()
    {
        // new trend? (else do things)
        if( this.trend.direction !== 'down' )
        {
            this.resetTrend();
            this.trend.direction = 'down';
            this.advice('short');
            if( this.debug ) log.info('Going short');
        }
        
        if( this.debug )
        {
            this.trend.duration++;
            log.info('Short since', this.trend.duration, 'candle(s)');
        }
    },
    
    
    /* END backtest */
    end: function()
    {
        let seconds = ((new Date()- this.startTime)/1000),
            minutes = seconds/60,
            str;
            
        minutes < 1 ? str = seconds.toFixed(2) + ' seconds' : str = minutes.toFixed(2) + ' minutes';
        
        log.info('====================================');
        log.info('Finished in ' + str);
        log.info('====================================');
    
        // print stats and messages if debug
        if(this.debug)
        {
            let stat = this.stat;
            log.info('BEAR RSI low/high: ' + stat.bear.min + ' / ' + stat.bear.max);
            log.info('BULL RSI low/high: ' + stat.bull.min + ' / ' + stat.bull.max);
            log.info('ADX min/max: ' + stat.adx.min + ' / ' + stat.adx.max);
        }
        
    }
    
};

module.exports = strat;

RSI_BULL_BEAR_ADX.toml

# SMA INDICATOR
SMA_long = 1000
SMA_short = 50

# RSI BULL / BEAR
BULL_RSI = 10
BULL_RSI_high = 80
BULL_RSI_low = 60
BEAR_RSI = 15
BEAR_RSI_high = 50
BEAR_RSI_low = 20

# MODIFY RSI (depending on ADX)
BULL_MOD_high = 5
BULL_MOD_low = -5
BEAR_MOD_high = 15
BEAR_MOD_low = -5

# ADX
ADX = 3
ADX_high = 70
ADX_low = 50

RSI_BULL_BEAR_PINGPONG

RSI_BULL_BEAR_PINGPONG.js

/*
    RSI Bull and Bear + ADX modifier
    1. Use different RSI-strategies depending on a longer trend
    2. But modify this slighly if shorter BULL/BEAR is detected
    -
    (CC-BY-SA 4.0) Tommie Hansen
    https://creativecommons.org/licenses/by-sa/4.0/
    
    UPDATE:
    3. Add pingPong for sideways market
    
    Rafael Martín.
*/

// req's
var log = require('../core/log.js');
var config = require('../core/util.js').getConfig();

// strategy
var strat = {
    
    /* INIT */
    init: function()
    {
        // core
        this.name = 'RSI Bull and Bear + ADX + PingPong';
        this.requiredHistory = config.tradingAdvisor.historySize;
        this.resetTrend();
        
        // debug? set to false to disable all logging/messages/stats (improves performance in backtests)
        this.debug = false;
        
        // performance
        config.backtest.batchSize = 1000; // increase performance
        config.silent = true;
        config.debug = false;
        
        // SMA
        this.addTulipIndicator('maSlow', 'sma', { optInTimePeriod: this.settings.SMA_long });
        this.addTulipIndicator('maFast', 'sma', { optInTimePeriod: this.settings.SMA_short });
        
        // RSI
        this.addTulipIndicator('BULL_RSI', 'rsi', { optInTimePeriod: this.settings.BULL_RSI });
        this.addTulipIndicator('BEAR_RSI', 'rsi', { optInTimePeriod: this.settings.BEAR_RSI });
        
        // ADX
        this.addTulipIndicator('ADX', 'adx', { optInTimePeriod: this.settings.ADX })
        
        // MOD (RSI modifiers)
        this.BULL_MOD_high = this.settings.BULL_MOD_high;
        this.BULL_MOD_low = this.settings.BULL_MOD_low;
        this.BEAR_MOD_high = this.settings.BEAR_MOD_high;
        this.BEAR_MOD_low = this.settings.BEAR_MOD_low;
        
        
        // debug stuff
        this.startTime = new Date();
        
        // add min/max if debug
        if( this.debug ){
            this.stat = {
                adx: { min: 1000, max: 0 },
                bear: { min: 1000, max: 0 },
                bull: { min: 1000, max: 0 }
            };
        }
        
        /* MESSAGES */
        
        // message the user about required history
        log.info("====================================");
        log.info('Running', this.name);
        log.info('====================================');
        log.info("Make sure your warmup period matches SMA_long and that Gekko downloads data if needed");
        
        // warn users
        if( this.requiredHistory < this.settings.SMA_long )
        {
            log.warn("*** WARNING *** Your Warmup period is lower then SMA_long. If Gekko does not download data automatically when running LIVE the strategy will default to BEAR-mode until it has enough data.");
        }
        
    }, // init()
    
    
    /* RESET TREND */
    resetTrend: function()
    {
        var trend = {
            duration: 0,
            direction: 'none',
            longPos: false, // this will be false or a price if we already have a long position
            pingPong : {
                gainsPercentage: this.settings.PINGPONG_GAINS_PERCENTAGE // when we want to close the long position?
            }
        };
    
        this.trend = trend;
    },
    
    
    /* get low/high for backtest-period */
    lowHigh: function( val, type )
    {
        let cur;
        if( type == 'bear' ) {
            cur = this.stat.bear;
            if( val < cur.min ) this.stat.bear.min = val; // set new
            else if( val > cur.max ) this.stat.bear.max = val;
        }
        else if( type == 'bull' ) {
            cur = this.stat.bull;
            if( val < cur.min ) this.stat.bull.min = val; // set new
            else if( val > cur.max ) this.stat.bull.max = val;
        }
        else {
            cur = this.stat.adx;
            if( val < cur.min ) this.stat.adx.min = val; // set new
            else if( val > cur.max ) this.stat.adx.max = val;
        }
    },
    
    
    /* CHECK */
    check: function()
    {
        // get all indicators
        let ind = this.tulipIndicators,
            maSlow = ind.maSlow.result.result,
            maFast = ind.maFast.result.result,
            rsi,
            adx = ind.ADX.result.result;
        
            
        // BEAR TREND
        if( maFast < maSlow )
        {
            rsi = ind.BEAR_RSI.result.result;
            let rsi_hi = this.settings.BEAR_RSI_high,
                rsi_low = this.settings.BEAR_RSI_low;
            
            // ADX trend strength?
            if( adx > this.settings.ADX_high ) rsi_hi = rsi_hi + this.BEAR_MOD_high;
            else if( adx < this.settings.ADX_low ) rsi_low = rsi_low + this.BEAR_MOD_low;
                
            if( rsi > rsi_hi ) this.short();
            else if( rsi < rsi_low ) this.long();
            //else this.pingPong();
            
            if(this.debug) this.lowHigh( rsi, 'bear' );
        }

        // BULL TREND
        else
        {
            rsi = ind.BULL_RSI.result.result;
            let rsi_hi = this.settings.BULL_RSI_high,
                rsi_low = this.settings.BULL_RSI_low;
            
            // ADX trend strength?
            if( adx > this.settings.ADX_high ) rsi_hi = rsi_hi + this.BULL_MOD_high;        
            else if( adx < this.settings.ADX_low ) rsi_low = rsi_low + this.BULL_MOD_low;
                
            if( rsi > rsi_hi ) this.short();
            else if( rsi < rsi_low )  this.long();
            else this.pingPong();
            
            if(this.debug) this.lowHigh( rsi, 'bull' );
        }
        
        // add adx low/high if debug
        if( this.debug ) this.lowHigh( adx, 'adx');
    
    }, // check()
    
    
    /* LONG */
    long: function()
    {
        if( this.trend.direction !== 'up' ) // new trend? (only act on new trends)
        {
            this.resetTrend();
            this.trend.direction = 'up';
            this.trend.longPos = this.candle.close;
            this.advice('long');
            if( this.debug ) log.info('Going long');
        }
        
        if( this.debug )
        {
            this.trend.duration++;
            log.info('Long since', this.trend.duration, 'candle(s)');
        }
    },
    
    
    /* SHORT */
    short: function()
    {
        // new trend? (else do things)
        if( this.trend.direction !== 'down' )
        {
            this.resetTrend();
            this.trend.direction = 'down';
            this.trend.longPos = false;
            this.advice('short');
            if( this.debug ) log.info('Going short');
        }
        
        if( this.debug )
        {
            this.trend.duration++;
            log.info('Short since', this.trend.duration, 'candle(s)');
        }
    },
    
    pingPong: function() {
        
        /**
        * Si actualmente tenemos una posicion long abierta vamos a comprobar si el precio 
        * actual del asset es un <gainsPercentage> más alto (trend.long + %gainsPercentage >= currentPrice)
        * y si es así cerramos la posición.
        */
        if (this.trend.longPos) {
            
            /**
            * Si tenemos una posicion long abierta pero la tendencia actual es bullish entonces 
            * no hacemos nada y dejamos que siga subiendo
            */
            //if (this.trend.direction == 'up') return;
            
            if (this.candle.close < (this.trend.longPos - (this.trend.longPos * (this.trend.pingPong.gainsPercentage / 3) / 100))) this.trend.longPos = this.candle.close; 
                        
            /**
            * Si no tenemos un porcentage de ganancias salimos de aqui
            */
            if (this.candle.close < (this.trend.longPos + (this.trend.longPos * this.trend.pingPong.gainsPercentage / 100) )) return;
            
            /**
            * Si hemos llegado hasta aqui significa que tenemos un long abierto, la tendencia actual es 
            * bajista y tenemos un <gainsPercentage> de ganancias, por lo tanto cerramos la posicion
            * para recoger ganancias y ponemos el longPos en false.
            */
            this.trend.longPos = false;
            this.advice('short');
        
        
        /**
        * Si hemos llegado hasta aqui significa que no tenemos ninguna posicion long abierta, por lo tanto 
        * podemos aprovechar para abrir una nueva posicion cuando sea el momento propicio.
        */
        } else {
            
            /**
            * Si estamos en tendencia bajista salimos de aqui sin hacer nada, asi dejamos que siga 
            * bajando y solo actuamos cuando la tendencia cambie a alcista (bullish).
            */
            if (this.trend.direction == 'down') return;
            
            /**
            * Si ha bajado al menos un <gains_percentage> abrimos un nuevo long
            */
            //if (this.candle.close < (this.trend.longPos - (this.trend.longPos * this.trend.pingPong.gainsPercentage / 100) )) return;

            
            /**
            * Si hemos llegado hasta aqui significa que se cumple los requisitos necesarios para volver a 
            * abrir una posicion long, por lo tanto ejecutamos un long y ademas guardamos el precio de la 
            * candle actual para saber a que precio hemos iniciado el long.
            */
            this.trend.longPos = this.candle.close;
            this.advice('long');
            
        }
    },
    
    
    /* END backtest */
    end: function()
    {
        let seconds = ((new Date()- this.startTime)/1000),
            minutes = seconds/60,
            str;
            
        minutes < 1 ? str = seconds.toFixed(2) + ' seconds' : str = minutes.toFixed(2) + ' minutes';
        
        log.info('====================================');
        log.info('Finished in ' + str);
        log.info('====================================');
    
        // print stats and messages if debug
        if(this.debug)
        {
            let stat = this.stat;
            log.info('BEAR RSI low/high: ' + stat.bear.min + ' / ' + stat.bear.max);
            log.info('BULL RSI low/high: ' + stat.bull.min + ' / ' + stat.bull.max);
            log.info('ADX min/max: ' + stat.adx.min + ' / ' + stat.adx.max);
        }
        
    }
    
};

module.exports = strat;

RSI_BULL_BEAR_PINGPONG.toml

# SMA INDICATOR
SMA_long = 1000
SMA_short = 50

# RSI BULL
BULL_RSI = 10
BULL_RSI_high = 80
BULL_RSI_low = 60

# RSI BEAR
BEAR_RSI = 15
BEAR_RSI_high = 50
BEAR_RSI_low = 20

# MODIFY RSI (depending on ADX)
BULL_MOD_high = 5
BULL_MOD_low = -5
BEAR_MOD_high = 15
BEAR_MOD_low = -5

# ADX
ADX = 3
ADX_high = 70
ADX_low = 50

# PING PONG
PINGPONG_GAINS_PERCENTAGE = 2

大家可以选择策略进行backtest,选择适合自己的参数。

欢迎大家加入gekko 知识星球, 在这里你可以得到,关于gekko环境搭建问题的解答/查看群主分享的交易机器人策略/加入gekko策略交流群组,以及获取更多的关于gekko使用方面的信息。
没有任何基础的小白也可以搭建自己的交易机器人。


gekko
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343