Back to Community
Buy 1 Share, Sell at Specific Price

I've been having trouble implementing a stop order for my algorithm.

Say for example if I want to buy 1 share of AAPL for $90, and sell at $100.

However this algorithm fulfills a much greater number of transactions than I need, as I only need 2. (1 Buy, 1 Sell)

def initialize(context):  
        context.aapl = sid(24)

def handle_data(context, data):  
        order(sid(24), 1,)  
        order(sid(24), -1, stop_price = 100)  

Thanks. Any help would be appreciated.

Clone Algorithm
9
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
def initialize(context):
    
    
    context.aapl = sid(24)
   
    
# Buys 1 Share of Each Stock   
def handle_data(context, data):
    order(sid(24), 1,)  
    order(sid(24), -1, stop_price = 100)
There was a runtime error.
10 responses

In the help page there is this example function that should help you. It uses percentage change in price to decide when to sell,but you can easily adapt it to your neeeds. Call this function from handle_data:

def check_positions_for_loss_or_profit(context, data):  
    # Sell our positions on longs/shorts for profit or loss  
    for security in context.portfolio.positions:  
        is_stock_held = context.stocks_held.get(security) >= 0  
        if data.can_trade(security) and is_stock_held and not get_open_orders(security):  
            current_position = context.portfolio.positions[security].amount  
            cost_basis = context.portfolio.positions[security].cost_basis  
            price = data.current(security, 'price')  
            # On Long & Profit  
            if price >= cost_basis * 1.10 and current_position > 0:  
                order_target_percent(security, 0)  
                log.info( str(security) + ' Sold Long for Profit')  
                del context.stocks_held[security]  
            # On Short & Profit  
            if price <= cost_basis* 0.90 and current_position < 0:  
                order_target_percent(security, 0)  
                log.info( str(security) + ' Sold Short for Profit')  
                del context.stocks_held[security]  
            # On Long & Loss  
            if price <= cost_basis * 0.90 and current_position > 0:  
                order_target_percent(security, 0)  
                log.info( str(security) + ' Sold Long for Loss')  
                del context.stocks_held[security]  
            # On Short & Loss  
            if price >= cost_basis * 1.10 and current_position < 0:  
                order_target_percent(security, 0)  
                log.info( str(security) + ' Sold Short for Loss')  
                del context.stocks_held[security]  

@Luca Thanks. I am still getting started with Quantopian, so I'm not quite sure what to change to make it reference AAPL, and stop order at a certain price.

Also https://www.quantopian.com/posts/take-profit, long and short integrated. And another that could be adapted.

@Blue Seahawk Thanks. I'll see if I can adapt it.

This should do what you are trying to do

Clone Algorithm
14
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
def initialize(context):
     
    context.aapl = sid(24)
   
    
# Buys 1 Share of Each Stock   
def handle_data(context, data):
    
    price = data.current(context.aapl, 'price')
    
    # if AAPL is not in portfolio and price <=90
    if context.aapl not in context.portfolio.positions and price <= 90:
        # buy Apple
        order(context.aapl, 1)
    
    # if AAPL is in portfolio and we haven't set the sell limit order yet, do it now
    elif context.aapl in context.portfolio.positions and not get_open_orders(context.aapl):
        # set a sell limit order at 110
        sell_price = 100
        order_target(context.aapl, 0, style=LimitOrder(sell_price))
There was a runtime error.

Thank you very much, Luca!

This is exactly what I was trying to do.

AAPL as one of the most high profile stocks is safe unless ordering a zillion shares.

More generally, for multiple stocks using LimitOrder, StopOrder or StopLimitOrder, considering partial fills, wait a minute, then set them on the amount filled, then continue to check open orders each minute and when the filled amount has changed, cancel the existing order and recreate with the new amount.

For example, from someone's algo, since I happen to have this available right now ...

                   Trading Minute  Action            Filled|Prev|Order  Sym  Price   Held  Limit|Stop  PnL  Lvrg OrderId  
2017-06-12 06:31 _t:401 INFO    1  Buy                          123192  XIV  79.56      _                0  0.00  bf49  
2017-06-12 06:32 _t:401 INFO    2    Bot                 1228|0|123192  XIV  79.57    1228              -7  0.01  bf49  
2017-06-12 06:33 _t:401 INFO    3    Bot              1040|1228|123192  XIV  79.45    2268            -161  0.02  bf49  
2017-06-12 06:34 _t:401 INFO    4    Bot              3093|2268|123192  XIV  79.53    5361               2  0.04  bf49  
2017-06-12 06:35 _t:401 INFO    5    Bot              1382|5361|123192  XIV  79.69    6743             852  0.05  bf49  
2017-06-12 06:36 _t:401 INFO    6    Bot              3058|6743|123192  XIV  79.76    9801            1305  0.08  bf49  
2017-06-12 06:37 _t:401 INFO    7    Bot               914|9801|123192  XIV  79.64   10715             124  0.09  bf49  
2017-06-12 06:38 _t:401 INFO    8    Bot             1322|10715|123192  XIV  79.38   12037           -2670  0.10  bf49  
2017-06-12 06:39 _t:401 INFO    9    Bot             1605|12037|123192  XIV  79.26   13642           -4124  0.11  bf49  

Minute 1 Order for 123192 shares

Minute 2 1228 shares are filled
Minute 2 Set a LimitOrder to sell 1228 shares at price .05 higher than cost_basis

Minute 3 An additional 1040 shares are filled
Minute 3 Cancel the previous LimitOrder
Minute 3 Set a new LimitOrder to sell the new number of shares held (2268) at price .05 higher than cost_basis

... etc

@Blue Seahawk Wow, this was actually exactly what I was trying to create.

So far I've been having trouble with canceling the previous limit orders and placing new ones. The result being, the algorithim places a far greater number of buy orders than necessary, and is just generally not within much manual control.

If you could please provide a couple of suggestions, or maybe the source code, it would help greatly!

@Blue Seahawk Also the SPY itself might be a good choice as the current volume is 136 million and the avg. volume is 66 million.

You can run something every minute like this. Instead of handle_data:

    for i in range(1, 391, 1):  # start, end + 1, every i  
        schedule_function(limits, date_rules.every_day(), time_rules.market_open(minutes=i))  

Then it's helpful to distinguish between opening and closing orders. Comes in handy a lot, cls_opn_crs(). Don't want to set a limit on a stock that is already in the process of closing for example, doubling up on closing orders would cause long to go short instead of zero. Aiming for universality, lots of stocks and including when there are partial fills, these are some of the essentials:

def cls_opn_crs(c, o):   # Identify the state of an order  
    # c = context, o is the order object  
    # https://www.quantopian.com/posts/order-state-on-partial-fills-close-open-or-crossover  
    if o.stop or o.limit: return 0   # assumes no stop or limit being used to open orders  
    if c.portfolio.positions[o.sid].amount * o.amount < 0:   # close or crossover (x)  
        if abs(c.portfolio.positions[o.sid].amount) < abs(o.amount - o.filled):  
            if abs(c.portfolio.positions[s].amount) - abs(o.filled) < 0:  
                  return 3  # crossed 0 (closed now opening portion of crossover)  
            else: return 2  # crossover closing  
        else:     return 0  # close, not x  
    else:         return 1  # open,  not x

def limits(context, data):  
    oos = get_open_orders()     # oos = open orders  
    for s in context.portfolio.positions:  
        if not data.can_trade(s): continue  
        limit_order = None; open_order = 0; opening = 0; do_limit = 0  
        for o in oos[s]:  
            open_order = 1  
            if o.limit:  
                limit_order = o                        # previous limit  
            elif cls_opn_crs(context, o) in [1, 3]:    # opening  
                opening = 1                            # partial fill underway  
        if not open_order and not limit_order:  # filled completely, needs limit  
            do_limit = 1  
        if opening and limit_order:             # busy opening  
            cancel_order(limit_order.id)        # cancel previous limit  
        if opening or not limit_order:  
            do_limit = 1  
        if do_limit:  
            cb    = context.portfolio.positions[s].cost_basis  
            amt   = context.portfolio.positions[s].amount  
            limit = float('%.2f' % (cb * (1 + (abs(amt) / amt) * .05))) # long or short  
            order_target(s, 0, style=LimitOrder(limit))  

Needs to be streamlined, I cobbled together limits() on the fly for you as a start, untested. Recommend vetting with debugger by clicking in margin on line numbers, high calorie code food even though it's about as fun as eating cardboard.
I'm not sure why you would have additional buys. You're surely already doing get_open_orders(security) from Luca's code and checking to only order if not already held. Another thing that can be useful is to wait after a position is closed, not reopening it right away or that would just waste some commission fees.

My code that includes both limits and trailing stops (not to get you down) is over 80 lines, part of a set of an integrated set of versatile tools that took too much effort for me to give away for altruism or 0.0 though. Over 1000 lines altogether, it does something like 30 things with options including the order tracking above. By the way I've seen people talk about investing a small amount of money around here, a small amount, and then they add, $1 million. If one of you would like to click on my name and ping me, feel free.