def TradeIfProfitable(ctx):

    ctx.volumeStep = 30
    
    alpha_slow = 0.015
    alpha_fast = 0.15

    slow = lambda: mathutils.ewma(alpha = alpha_slow)
    fast = lambda: mathutils.ewma(alpha = alpha_fast)

    linear_signal = signal.RandomWalk(initialValue=200, 
                                      deltaDistr=const(-1), 
                                      label="200-t")
    
    demo = ctx.addGraph('demo')
    myVolume = lambda: [(observable.VolumeTraded(), demo)]
    myAverage = lambda alpha: [(observable.avg(observable.Price(orderbook.OfTrader()), alpha), demo)]
    
    avg_plus = strategy.TwoAverages(average1 = slow(), 
                                    average2 = fast(),
                                    creationIntervalDistr = mathutils.constant(1.),
                                    volumeDistr           = mathutils.constant(1.))
    
    avg_minus = strategy.TwoAverages(average1 = fast(), 
                                     average2 = slow(),
                                     creationIntervalDistr = mathutils.constant(1.),
                                     volumeDistr           = mathutils.constant(1.))
    
    avg_plus_opt = strategy.TradeIfProfitable(avg_plus)
    avg_minus_opt = strategy.TradeIfProfitable(avg_minus)

    return [
        ctx.makeTrader_A(strategy.LiquidityProvider(volumeDistr=const(45)),
                         "liquidity"),

        ctx.makeTrader_A(strategy.Signal(linear_signal,
                                         volumeDistr=const(20)), 
                        "signal", 
                        [(linear_signal, ctx.amount_graph)]),
            
        ctx.makeTrader_A(avg_plus, 
                        'avg+', 
                        myAverage(alpha_slow) + myAverage(alpha_fast) + myVolume()),

        ctx.makeTrader_A(avg_minus, 
                         'avg-',
                         myVolume()),

        ctx.makeTrader_A(avg_plus_opt, 
                         'avg+ opt',
                         myVolume()),

        ctx.makeTrader_A(avg_minus_opt, 
                         'avg- opt',
                         myVolume()),
    ]
def ChooseTheBest(ctx):

    ctx.volumeStep = 30
    
    slow_alpha = 0.015
    fast_alpha = 0.15

    linear_signal = signal.RandomWalk(initialValue=200, 
                                      deltaDistr=const(-1), 
                                      label="200-t")
    
    demo = ctx.addGraph('demo')
    myVolume = lambda: [(observable.VolumeTraded(), demo)]
    myAverage = lambda alpha: [(observable.avg(observable.MidPrice(orderbook.OfTrader()), alpha), demo)]
    
    def cross(alpha1, alpha2):
        return strategy.TwoAverages(
                    event.Every(const(1.)),
                    order.factory.side.Market(volume = const(1.)),
                    alpha1, alpha2)
        
    def strategies():
        return [cross(slow_alpha, fast_alpha), cross(fast_alpha, slow_alpha)]
        
    return [
        ctx.makeTrader_A(strategy.v0.LiquidityProvider(volumeDistr=const(45)),
                         "liquidity"),

        ctx.makeTrader_A(strategy.Signal(event.Every(const(1.)),
                                         order.factory.side.Market(volume = const(20)),
                                         linear_signal), 
                        "signal", 
                        [(linear_signal, ctx.amount_graph)]),
            
        ctx.makeTrader_A(cross(slow_alpha, fast_alpha), 
                        'avg+', 
                        myAverage(slow_alpha) + myAverage(fast_alpha) + myVolume()),
 
        ctx.makeTrader_A(cross(fast_alpha, slow_alpha), 
                         'avg-',
                         myVolume()),

        ctx.makeTrader_A(strategy.ChooseTheBest(
                                    strategies(), 
                                    strategy.adaptive.virtualMarket), 
                         'best virt',
                         myVolume()),

        ctx.makeTrader_A(strategy.ChooseTheBest(
                                    strategies(), 
                                    strategy.adaptive.account), 
                         'best real',
                         myVolume()),
    ]
def TwoAverages(ctx):

    ctx.volumeStep = 30

    alpha_slow = 0.015
    alpha_fast = 0.15

    linear_signal = signal.RandomWalk(initialValue=200, deltaDistr=const(-1), label="200-t")

    demo = ctx.addGraph("demo")
    myVolume = lambda: [(observable.VolumeTraded(), demo)]
    myAverage = lambda alpha: [(observable.avg(observable.MidPrice(orderbook.OfTrader()), alpha), demo)]

    return [
        ctx.makeTrader_A(
            strategy.LiquidityProvider(event.Every(ops.constant(1.0)), order.factory.sideprice.Limit(volume=const(10))),
            "liquidity",
        ),
        ctx.makeTrader_A(
            strategy.Signal(event.Every(ops.constant(1.0)), order.factory.side.Market(volume=const(3)), linear_signal),
            "signal",
            [(linear_signal, ctx.amount_graph)],
        ),
        ctx.makeTrader_A(
            strategy.v0.TwoAverages(
                ewma_alpha1=alpha_slow, ewma_alpha2=alpha_fast, creationIntervalDistr=const(1.0), volumeDistr=const(1.0)
            ),
            "avg+",
            myAverage(alpha_slow) + myAverage(alpha_fast) + myVolume(),
        ),
        ctx.makeTrader_A(
            strategy.v0.TwoAverages(
                ewma_alpha2=alpha_slow, ewma_alpha1=alpha_fast, creationIntervalDistr=const(1.0), volumeDistr=const(1.0)
            ),
            "avg-",
            myVolume(),
        ),
        ctx.makeTrader_A(
            strategy.TwoAverages(
                event.Every(ops.constant(1.0)), order.factory.side.Market(volume=const(1.0)), alpha_slow, alpha_fast
            ),
            "avg_ex+",
            myVolume(),
        ),
        ctx.makeTrader_A(
            strategy.TwoAverages(
                event.Every(ops.constant(1.0)), order.factory.side.Market(volume=const(1.0)), alpha_fast, alpha_slow
            ),
            "avg_ex-",
            myVolume(),
        ),
    ]
def MeanReversion(ctx):

    ctx.volumeStep = 40

    alpha = 0.015
    V = 1
    linear_signal = signal.RandomWalk(initialValue=200, 
                                      deltaDistr=const(-1), 
                                      label="200-t")

    demo = ctx.addGraph('demo')
    myVolume = lambda: [(observable.VolumeTraded(), demo)]
    myAverage = lambda: [(observable.avg(observable.MidPrice(orderbook.OfTrader()), alpha), demo)]
    myPrice = lambda: [(observable.MidPrice(orderbook.OfTrader()), demo)]

    return [
        ctx.makeTrader_A( 
                       strategy.v0.LiquidityProvider(
                            volumeDistr=const(V*20), 
                            orderFactoryT=order.WithExpiryFactory(
                                expirationDistr=const(10))),
                       label="liquidity"),
    
        ctx.makeTrader_A(strategy.Signal(
                                event.Every(ops.constant(1.)),
                                order.factory.side.Market(volume = const(V*3)),
                                linear_signal), 
                         "signal", 
                         [(linear_signal, ctx.amount_graph)]),
     
        ctx.makeTrader_A(strategy.v0.MeanReversion(
                                ewma_alpha=(alpha),
                                creationIntervalDistr = ops.constant(1.),
                                volumeDistr = const(V)),
                         "meanreversion", 
                         myVolume() + myAverage() + myPrice()),
     
        ctx.makeTrader_A(
                strategy.MeanReversion(
                    event.Every(ops.constant(1.)),
                    order.factory.side.Market(volume = const(V)),
                    alpha),
                 "meanreversion_ex", 
                 myVolume()),
    ]    
def TrendFollower(ctx):

    V = 1
    alpha = 0.015
    ctx.volumeStep = 30

    linear_signal = signal.RandomWalk(initialValue=200, 
                                      deltaDistr=const(-1), 
                                      label="200-t")
    
    demo = ctx.addGraph('demo')
    myVolume = lambda: [(observable.VolumeTraded(), demo)]
    myAverage = lambda alpha: [(observable.avg(observable.Price(orderbook.OfTrader()), alpha), demo)]
    
    return [
            ctx.makeTrader_A(strategy.LiquidityProvider(
                                volumeDistr=const(V*8), 
                                orderFactoryT=order.WithExpiryFactory(
                                    expirationDistr=const(100))),
                             label="liquidity"),
    
            ctx.makeTrader_A(strategy.Signal(linear_signal, 
                                             volumeDistr = const(V*2)), 
                            "signal", 
                            [
                             (linear_signal, ctx.amount_graph)
                            ]),
    
            ctx.makeTrader_A(strategy.TrendFollower(
                                    creationIntervalDistr = mathutils.constant(1.),
                                    average=mathutils.ewma(alpha),
                                    volumeDistr = const(V)),
                             "trendfollower", 
                             myVolume() + myAverage(alpha)),
            
            ctx.makeTrader_A(strategy.TrendFollowerEx(
                                       creationIntervalDistr = mathutils.constant(1.),
                                       average=mathutils.ewma(alpha),
                                       volumeDistr = const(V)),
                             "trendfollower_ex",
                             myVolume())
    ]
def TradeIfProfitable(ctx):

    ctx.volumeStep = 30

    slow_alpha = 0.015
    fast_alpha = 0.15

    linear_signal = signal.RandomWalk(initialValue=200, deltaDistr=const(-1), label="200-t")

    demo = ctx.addGraph("demo")
    myVolume = lambda: [(observable.VolumeTraded(), demo)]
    myAverage = lambda alpha: [(observable.avg(observable.MidPrice(orderbook.OfTrader()), alpha), demo)]

    def cross(alpha1, alpha2):
        return strategy.TwoAverages(
            event.Every(ops.constant(1.0)), order.factory.side.Market(volume=const(1.0)), alpha1, alpha2
        )

    avg_plus_virt = strategy.TradeIfProfitable(cross(slow_alpha, fast_alpha), strategy.adaptive.virtualMarket)
    avg_minus_virt = strategy.TradeIfProfitable(cross(fast_alpha, slow_alpha), strategy.adaptive.virtualMarket)

    avg_plus_real = strategy.TradeIfProfitable(cross(slow_alpha, fast_alpha), strategy.adaptive.account)
    avg_minus_real = strategy.TradeIfProfitable(cross(fast_alpha, slow_alpha), strategy.adaptive.account)

    return [
        ctx.makeTrader_A(strategy.v0.LiquidityProvider(volumeDistr=const(45)), "liquidity"),
        ctx.makeTrader_A(
            strategy.Signal(event.Every(ops.constant(1.0)), order.factory.side.Market(volume=const(20)), linear_signal),
            "signal",
            [(linear_signal, ctx.amount_graph)],
        ),
        ctx.makeTrader_A(
            cross(slow_alpha, fast_alpha), "avg+", myAverage(slow_alpha) + myAverage(fast_alpha) + myVolume()
        ),
        ctx.makeTrader_A(cross(fast_alpha, slow_alpha), "avg-", myVolume()),
        ctx.makeTrader_A(avg_plus_virt, "avg+ virt", myVolume()),
        ctx.makeTrader_A(avg_minus_virt, "avg- virt", myVolume()),
        ctx.makeTrader_A(avg_plus_real, "avg+ real", myVolume()),
        ctx.makeTrader_A(avg_minus_real, "avg- real", myVolume()),
    ]
def MultiarmedBandit(ctx):

    ctx.volumeStep = 30
        
    demo = ctx.addGraph('demo')
    myVolume = lambda: [(observable.VolumeTraded(), demo)]
    myAverage = lambda alpha: [(observable.avg(observable.MidPrice(orderbook.OfTrader()), alpha), demo)]
    
    def fv(x):
        return  strategy.FundamentalValue(
                    event.Every(ops.constant(1.)),
                    order.factory.side.Market(volume = const(1.)),
                    fundamentalValue = const(x))
                                        
    xs = range(100, 300, 50) + range(160, 190, 10)
    def strategies():
        return map(fv, xs)
    
    def fv_traders():
        return [ctx.makeTrader_A(fv(x), "fv" + str(x), myVolume()) for x in xs]
        
    return [
        ctx.makeTrader_A(strategy.v0.LiquidityProvider(volumeDistr=const(45)),
                         "liquidity"),
            
        ctx.makeTrader_A(        
                strategy.FundamentalValue(
                    event.Every(ops.constant(1.)),
                    order.factory.side.Market(volume = const(12.)),
                    fundamentalValue = const(200)),
                'fv 12-200'), 

        ctx.makeTrader_A(strategy.MultiarmedBandit(
                                    strategies(), 
                                    strategy.adaptive.virtualMarket,
                                    strategy.adaptive.weight.efficiencyTrend), 
                         'virt trend',
                         myVolume()),

        ctx.makeTrader_A(strategy.MultiarmedBandit(
                                    strategies(), 
                                    strategy.adaptive.account,
                                    strategy.adaptive.weight.efficiencyTrend), 
                         'real trend',
                         myVolume()),

        ctx.makeTrader_A(strategy.MultiarmedBandit(
                                    strategies(), 
                                    strategy.adaptive.virtualMarket,
                                    strategy.adaptive.weight.efficiency), 
                         'virt efficiency',
                         myVolume()),

        ctx.makeTrader_A(strategy.MultiarmedBandit(
                                    strategies(), 
                                    strategy.adaptive.account,
                                    strategy.adaptive.weight.efficiency), 
                         'real efficiency',
                         myVolume()),

        ctx.makeTrader_A(strategy.MultiarmedBandit(
                                    strategies(), 
                                    strategy.adaptive.virtualMarket,
                                    strategy.adaptive.weight.score, 
                                    strategy.adaptive.weight.identity), 
                         'virt score',
                         myVolume()),

        ctx.makeTrader_A(strategy.MultiarmedBandit(
                                    strategies(), 
                                    strategy.adaptive.account,
                                    strategy.adaptive.weight.score, 
                                    strategy.adaptive.weight.identity), 
                         'real score',
                         myVolume()),

        ctx.makeTrader_A(strategy.MultiarmedBandit(
                                    strategies(), 
                                    strategy.adaptive.virtualMarket,
                                    strategy.adaptive.weight.efficiencyTrend, 
                                    strategy.adaptive.weight.identity, 
                                    strategy.adaptive.weight.chooseTheBest), 
                         'virt best',
                         myVolume()),

        ctx.makeTrader_A(strategy.MultiarmedBandit(
                                    strategies(), 
                                    strategy.adaptive.account,
                                    strategy.adaptive.weight.unit,
                                    strategy.adaptive.weight.identity), 
                         'uniform',
                         myVolume()),

    ] + fv_traders()