Welcome, guest | Sign In | My Account | Store | Cart

Simple Engine to help understand how to best wager your next bet, given that you just made a loss. The engine uses the modified Powell method to optimise the weight to apply to your wager on the next position.

{'My Simple Heads And Tails Model': <BackTest.Simulation object at 0x0583D410>} participants [100] survivors [90.0%] losers [10.0%] weight [0.073858] solving for r: [ 0.07385806] simulations 100, trials 100 starting pot 1000 calling initialise {'My Simple Heads And Tails Model': <BackTest.Simulation object at 0x0583D430>} participants [100] survivors [86.0%] losers [14.0%] weight [0.072220] solving for r: [ 0.07221954] Optimization terminated successfully. Current function value: 8.000000 Iterations: 2 Function evaluations: 30 highest survivability following loss, multiply wager by 7.2949 %

.

Ran 2 tests in 25.545s

OK

Python, 441 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
'''
    monte carlo tool for simple strategy, more generally for use with any
    strategy that I want to back test...

    Engine takes a class instance, derived from a base class wih two methods
    
    initialise()
    onsimulation()
    aftersimulation()
    ontrial()
    finalise()


'''

import unittest, datetime
import numpy as np
from BackTest import MonteCarloModel, MonteCarloEngine, Simulation 
import matplotlib.pyplot as plt
from random import randint 
from scipy.optimize import fmin_powell
from hashlib import md5
from time import localtime

def Root2(r,verbose=True):
    '''
        simple wrapper routine for solver. returns the energy level for a given R=r.
        the solver can use this method to minimise the energy by varying r as necessary.
    '''
    if r <= 0:
        return 1e99
    else:
        e = MonteCarloEngine(moduleName='MonteCarloHeadsTailsExample', className='SimpleHeadTailModel')
        losers = e.start(args={'wager_multiplier':r})
        if verbose: print 'solving for r: ', r
        return losers              
        

class SimpleHeadTailModel(MonteCarloModel):
    '''
      model wager
      previous bet success or not, impact to profit.
        
    '''
    
    def toss(self):
        '''
            1 - win
            -1 - loss
            Each toss determines whether the position is successful or not. This way no need to keep track of a decision
            and an associated variable. Simply do I win or not.
        '''
        coin_toss = randint(1,2)
        if coin_toss == 1:
            return 1
        else:
            return -1
            
    def initialise(self, context):
                
        self.name = 'My Simple Heads And Tails Model'
        # start with 10 USD bet
        self.wager= 100
        self.wager_initial= 100
        self.starting_pot = 1000
        
        self.previous_value = 1 # default to 1 on first round
        self.simulations = 100    # MC simulation trials        
        self.trials = 100   # subintervals

        self.r = np.zeros(shape=(self.simulations, self.trials), dtype=float) # matrix to hold all results
        self.pnl = np.zeros(shape=(self.simulations, self.trials), dtype=float) # matrix to hold all results
        print "simulations %d, trials %d starting pot %d " % (self.simulations, self.trials, self.starting_pot)
        
        # Tell the engine where to associate the data to security.        
        context[self.name] = Simulation(self.simulations, self.trials, self.toss)
    
        self.fig = plt.figure()
        self.ax = self.fig.add_subplot(211)
        self.ax1 = self.fig.add_subplot(212)
        self.ax.autoscale_view(True,True,True)        
                        
    
    def onsimulation(self, model, simulation, engine):        
        self.r[simulation,0] = 0
        # assume starting pot here
        self.pnl[simulation,0] = self.starting_pot
        
    def aftersimulation(self, model, simulation, engine):
        self.ax.plot(np.arange(0, self.trials, 1), self.r[simulation])        
        self.ax1.plot(np.arange(0, self.trials, 1), self.pnl[simulation])
        
    def reset_wager(self):
        self.wager = self.wager_initial
        
    def ontrial(self, model, simulation, trial, value, engine, args):
        '''
            want to test some strategies for betting
            set wager for each bet
            if previous bet

            value : float
                sample from model
            
        '''
                     
	   
        # if we lost last time then double up		
		
        if self.previous_value == -1:
		if args.has_key('args'):
                	self.wager = (self.wager*float(args['args']['wager_multiplier'][0]))
		else:
			self.wager = (self.wager*0.1)      
        
        # keep track of coin toss paths
        self.r[simulation,trial] = self.r[simulation,trial-1] + value
        if args.has_key('args'):
            self.r0 = float(args['args']['wager_multiplier'][0])
        else:
			self.r0 =0.1
        # if we won, add the wager
        # else subtract the wager
        
        if self.pnl[simulation,trial-1] > 0:        
            if value == 1 :
                self.pnl[simulation,trial] = self.pnl[simulation,trial-1] + self.wager
            else:
                self.pnl[simulation,trial] = self.pnl[simulation,trial-1] - self.wager
        else:
            # no bet to be made here
            self.pnl[simulation,trial] = self.pnl[simulation,trial-1]
             
        # always reset wager    
        self.reset_wager()
        
        # keep track of the previous value for next time around
        self.previous_value = value
        
	def add_prefix(self, filename):
		from hashlib import md5
		from time import localtime
		return "%s_%s"%(md5(str(localtime())).hexdigest(), filename)	
		
    def finalise(self, model, engine):  
		'''
			returns the value that we are trying to minimise, here the number of losers.
		'''
        
	# what is our survivability

		number_of_losers = len([f for f in self.pnl if f[len(f)-1]<=0])
		number_of_survivors = len([f for f in self.pnl if f[len(f)-1]>0])
		number_of_participants = len(self.pnl)
		print "participants [%d] survivors [%2.1f%%] losers [%2.1f%%] weight [%2.6f] "% (number_of_participants, float(number_of_survivors)/float(number_of_participants)*100, float(number_of_losers)/float(number_of_participants)*100, self.r0)

		plt.title('Simulations %d Steps %d' % (int(self.simulations), int(self.trials)))
		plt.xlabel('steps')
		plt.ylabel('profit and loss')					
		plt.savefig("%s_%s"%(md5(str(localtime())).hexdigest(), 'model'))
		return float(number_of_losers)/float(number_of_participants)*100
        
		
class TestNode(unittest.TestCase):
    def setUp(self):
        pass    
   
    def test_engine(self):
        '''
            example of how to launch the MontoCarloTestEngine
            this is modelled on the quantopian style interface.
        '''		
        e = MonteCarloEngine(moduleName='MonteCarloHeadsTailsExample', className='SimpleHeadTailModel')
        e.start()
    
    def test_minimise(self):
                
        print '#################################'
        print '# Test Equilibrium Loss Wager'
        print '#################################'
        
        wager_multiplier=fmin_powell(Root2, x0=1., maxiter=20)
        print "highest survivability following loss, multiply wager by %2.4f %% "%(wager_multiplier*100)

if __name__ == '__main__':
    unittest.main()


==================================================================
== BackTest module
==================================================================


'''
	back testing tool for prediction strategy, more generally for use with any
	strategy that I want to back test...

	Engine takes a class instance, derived from a base class wih twomethods

	
	initialise()
	ondata()


'''

import unittest, time, datetime
from pandas import DataFrame
import numpy as np
from pylab import show
import random
from abc import ABCMeta, abstractmethod
import pandas as pd

#
# Simple python component wrapper
#

class Component(object):
	__metaclass__ = ABCMeta
	
	@abstractmethod
	def start(self):
		raise NotImplementedError("Should implement intialise()!")
		

class BackTestModel(object):
	__metaclass__ = ABCMeta
	
	@abstractmethod
	def initialise(self, context):
		raise NotImplementedError("Should implement intialise()!")
	
	@abstractmethod	
	def ondata(self, sid, data):
		raise NotImplementedError("Should implement ondata()!")			
	
class MonteCarloModel(object):
	__metaclass__ = ABCMeta
	
	@abstractmethod
	def initialise(self, context):
		raise NotImplementedError("Should implement intialise()!")
	
	@abstractmethod	
	def ontrial(self, model, simulation, trial, value, engine, args):
		raise NotImplementedError("Should implement ontrial()!")
	
	def onsimulation(self, model, simulation, engine):
		raise NotImplementedError("Should implement onsimulation()!")
	
	def aftersimulation(self, model, simulation, engine):
		raise NotImplementedError("Should implement aftersimulation()!")
	
	def finalise(self, model, engine):
		raise NotImplementedError("Should implement finalise()!")
	
	
class Simulation(object):
	'''
		simple wrapper that describes a simulation
	'''
	
	def __init__(self, n, m, func):
		'''
			n integer
				number of simulations
			m integer
				number of trials per simulation
			func class method or function
				used to sample the value
		'''
		self.number_of_simulations = n
		self.number_of_trials = m
		self.func = func	
		
	@property
	def sample(self):
		return self.func
	
class MonteCarloEngineException(Exception):
	pass	
	
class MonteCarloEngine(Component):
		'''
			twist on the Engine that will take a different type of context, this time
			a Simulation class instance. This will be called
			
			
			class ExampleModel(MonteCarloModel):

				def initialise(self, context):
					context['My Simple Model'] = Simulation(10, 100, standard_normal()) 
					print 'setting My Simple Model' 
					
				def ondata(self, model, simulation, trial, value, engine):
					print simulation, trial, value, engine
			 
		'''
		def __init__(self, moduleName, className):
			self.context = {}			
			self.obj = self.__generate__(moduleName, className)
			#print isinstance(self.obj, MonteCarloModel), hasattr(self.obj, 'initialise')
			if isinstance(self.obj, MonteCarloModel):
				if hasattr(self.obj, 'initialise'):
					self.obj.initialise(self.context)
					print 'calling initialise'
				else:
					print 'no initialise'
			#
			# TODO: load data from somewhere for securities in context
			#	
			print self.context	
		
		def __generate__(self, module_name, class_name):
			module = __import__(module_name)
			class_ = getattr(module, class_name)
			instance = class_()
			#print instance 
			return instance

		def start(self, **args):
			#print 'starting...', self.obj, self.context, args		
			if self.obj is None:
				raise MonteCarloEngineException('No engine exists')
		 	
			for name, model in self.context.items():										
				for simulation in np.arange(0, model.number_of_simulations): # number of MC simulations
						# call to signal new simulation
						if hasattr(self.obj, 'onsimulation'):
							self.obj.onsimulation(model, simulation, self)
							
						for trial in np.arange(1,model.number_of_trials): #trials per simulation						
							value = model.sample()				
							if hasattr(self.obj, 'ontrial'):								
								self.obj.ontrial(model, simulation, trial, value, self, args)
																
						# call to signal after simulation
						if hasattr(self.obj, 'aftersimulation'):
							self.obj.aftersimulation(model, simulation, self)					
					#self.post_ondata(k, index2, value)
							
			if hasattr(self.obj, 'finalise'):
				return self.obj.finalise(model, self)
	
'''
class ExampleModel(BackTestModel):

	def initialise(self, context):
		context['ARM.L'] = 'Book1.csv'
		print 'setting ARM.L' 
		
	def ondata(self, sid, data):
		print sid, data
'''
class Engine(Component):
	'''
		responsible for handling instances of the back test models
	'''
	def __init__(self, moduleName, className):
		
		self.context = {}
		self.data = {}
		self.orders = {}
		self.positions = {}
		self.pnl = {}
		self.risk = {}

		self.obj = self.__generate__(moduleName, className)
		#print isinstance(self.obj, BackTestModel), hasattr(self.obj, 'initialise')
		if isinstance(self.obj, BackTestModel):
			if hasattr(self.obj, 'initialise'):
				self.obj.initialise(self.context)
				#print 'calling initialise'
			else:
				print 'no initialise'
		#
		# TODO: load data from somewhere for securities in context
		#	
		#print self.context	
		for k in self.context.keys():
			#print k
			t = time.clock()
			myfilename = self.context[k]
		      	data = DataFrame.from_csv(myfilename,header=0,index_col=0,parse_dates=True)	
			print 'load data', time.clock()-t						
			self.data[k] = data
			self.positions[k] = 0
			self.pnl[k] = 0
			self.risk[k] = 0
	
	def order(self, sid, value):
		# queue order to be processed
		self.orders[sid] = (value, False)
	
	@property
	def position(self):
		return self.positions
	
	def __generate__(self, module_name, class_name):
		module = __import__(module_name)
		class_ = getattr(module, class_name)
		instance = class_()
		print instance 
		return instance
	
	def post_ondata(self, sid, index, value):
		# process orders
		for k in self.context.keys():
			if hasattr(self, 'orders'):
				if len(self.orders) == 0:
					print 'no orders'
					break			
				
			m_size, m_processed = self.orders[k]
			# check we have not processed this order already.
			if not m_processed:
				if not (self.positions[k]+ m_size <= 0):				
					self.positions[k] += m_size
					print 'ordering %d of %s, total %d' % (m_size, k, self.positions[k])
					self.orders[k] = None
				else:
					print 'no short selling'				
		# handle pnl and risk
		# tick() charts
		

	def start(self):
		print 'starting...', self.obj, self.context		
		if not self.obj is None:	
			for k in self.context:
				for i, (index, value) in enumerate(self.data[k]['value'].iteritems()):					
					index2 = datetime.datetime(pd.to_datetime(index).year
											, pd.to_datetime(index).month
											, pd.to_datetime(index).day)					
					self.obj.ondata(k
								, index2
								, value
								, self.data[k]['value'][0:i]
								, self)					
					self.post_ondata(k, index2, value)