1

I am scratching my head on this, as I am really confused. I am trying to compute a moving average on a numpy array. The numpy array is loaded from a txt file.

I also try to print my smas function (the moving average that I am computing on the loaded data) and fail to do so!

here is the code.

def backTest():
    portfolio = 50000
    tradeComm = 7.95

    stance = 'none'
    buyPrice = 0
    sellPrice = 0
    previousPrice = 0

    totalProfit = 0

    numberOfTrades = 0
    startPrice = 0


    startTime = 0
    endTime = 0
    totalInvestedTime = 0
    overallStartTime = 0
    overallEndTime = 0

    unixConvertToWeeks = 7*24*60*60
    unixConvertToDays = 24*60*60
    date, closep, highp, lowp, openp, volume = np.genfromtxt('AAPL2.txt', delimiter=',', unpack=True,
                                                          converters={ 0: mdates.strpdate2num('%Y%m%d')})


    window = 20
    weights = np.repeat(1.0, window)/window
    smas = np.convolve(closep, weights, 'valid')

    prices = closep[19:]

    for price in prices:
        if stance == 'none':
            if prices > smas:
                print "buy triggered"
                buyPrice = closep
                print "bought stock for", buyPrice
                stance = "holding"
                startTime = unixStamp
                print 'Enter Date:', time.strftime('%m/%d/%Y', time.localtime(startTime))

            if numberOfTrades == 0:
                startPrice = buyPrice
                overallStartTime = unixStamp

            numberOfTrades += 1


        elif stance == 'holding':
            if prices < smas:
                print 'sell triggered'
                sellPrice = closep
                print 'finished trade, sold for:',sellPrice
                stance = 'none'
                tradeProfit = sellPrice - buyPrice
                totalProfit += tradeProfit
                print totalProfit
                print 'Exit Date:', time.strftime('%m/%d/%Y', time.localtime(endTime))
                endTime = unixStamp
                timeInvested = endTime - startTime
                totalInvestedTime += timeInvested

                overallEndTime = endTime

                numberOfTrades += 1

        previousPrice = closep

here is the error:

 Traceback (most recent call last):
  File "C:\Users\antoniozeus\Desktop\backtester2.py", line 180, in <module>
backTest()
  File "C:\Users\antoniozeus\Desktop\backtester2.py", line 106, in backTest
if prices > smas:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
antonio_zeus
  • 477
  • 2
  • 11
  • 21

2 Answers2

1

If you have a 1-D numpy array, there's a really slick way of doing moving averages using cumsum (via https://stackoverflow.com/a/14314054/1345536):

def moving_average(a, n=3) :
    ret = np.cumsum(a, dtype=float)
    ret[n:] = ret[n:] - ret[:-n]
    return ret[n - 1:] / n

Your code snippet has a lot of code that is extraneous to the problem at hand.

Community
  • 1
  • 1
Travis D.
  • 342
  • 1
  • 9
  • He only used one line for that: `np.convolve(DATA_TO_MA, weights, 'valid')` – CT Zhu Apr 05 '14 at 20:08
  • 1
    Right. In which case, this should probably be submitted to http://codereview.stackexchange.com instead? PS -- Didn't know about 'valid' option for convolve; that's a much better approach. Very cool; thanks! – Travis D. Apr 05 '14 at 20:16
  • `valid` control the behavior of the moving average, here especially when `DATA_TO_MA` is shorter than `Weights`. Try `np.convolve(range(10), np.repeat(1.0, 20)/20, 'full')` V.S. `same` or `valid` – CT Zhu Apr 05 '14 at 20:22
  • `range(10)` give you `[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]`. Just to make up something that is shorter than `np.repeat(1.0, 20)/20` – CT Zhu Apr 05 '14 at 20:47
  • i have edited my script, see above. the for loop still doesnt solve my issue. – antonio_zeus Apr 06 '14 at 16:35
1

Change closep > smas to closep[-1] > smas[-1] or closep[0] > smas[0]should be the solution, according to your intended behavior.

Whether to closep[-1] > smas[-1] or closep[0] > smas[0] depends on your data: the most current price, is it the last row of the txt file, or the first in the txt file? Double check that.

To get all the possible 'buy triggers' and their closing prices, without using a loop:

if stance == 'none':
    buyPrice_list=closep[19:][closep[19:] > smas] #change it to [:-19] if the current price is the first row.

Then buyPrice_list stores all the closing prices at buy triggers. See Boolean indexing, http://wiki.scipy.org/Cookbook/Indexing.

CT Zhu
  • 52,648
  • 17
  • 120
  • 133
  • one problem with this - is that I needed to change closep[19:] > smas because i got an error: 'ValueError: operands could not be broadcast together with shapes (522) (503)' – antonio_zeus Apr 05 '14 at 20:38
  • No, you are interested in the current closing price, rather than that ALL previous 522 closing prices have to be higher than SMA. So, no, just get the most current by slice both `array`s by `[0]` or `[-1]` depending on your data. If you want to do the latter, you need `(closep[19:] > smas).all()` – CT Zhu Apr 05 '14 at 20:42
  • so I followed those inxs, and noticed that the backtester immediately stops... because it is not a loop, I am simply looking at one period. but I have an array of closing prices and an array of moving averages... – antonio_zeus Apr 05 '14 at 20:45
  • okay -tried this as well and created a new error.. really sorry that some of this stuff I do not understand ' File "C:/Users/antoniozeus/Desktop/backtester2.py", line 173, in backTest() File "C:/Users/antoniozeus/Desktop/backtester2.py", line 104, in backTest buyPrice_list=closep[-19:][closep[-19]>smas] ValueError: too many boolean indices' – antonio_zeus Apr 05 '14 at 21:22
  • LOL okay, true, but now this: File "C:/Users/antoniozeus/Desktop/backtester2.py", line 104, in backTest buyPrice_list=closep[-19:][closep[-19:]>smas] ValueError: operands could not be broadcast together with shapes (19) (503) – antonio_zeus Apr 05 '14 at 21:28
  • hold on! i think i know whats happening – antonio_zeus Apr 05 '14 at 21:34
  • should be `closep[:-19]`, right? Otherwise you are picking the LAST 19 elements. – CT Zhu Apr 05 '14 at 21:43
  • i have added a for loop and still get the same error. Check out prices now, its starts 19 data points inward since my moving average of 20 need to be of same length – antonio_zeus Apr 06 '14 at 16:34