# -*- coding: utf-8 -*-
"""
Created on Thu Mar 21 17:01:08 2019
@author: Costantini L., Mazza M., Sabbatini G.
"""
import random as rd
import matplotlib.pylab as plt
import pandas as pd
import numpy as np
from xcs import XCSAlgorithm
from xcs.scenarios import ScenarioObserver
from xcs.scenarios import Scenario
from xcs.bitstrings import BitString
import datetime
#function which compute the moving avarage of a certain serie of data
def MA(data,T):
ma=[]
for i in range(len(data)):
S=0
if(i<T):
ma.append(0)
else:
for k in range(T):
S+= data[i-k]
ma.append(S/T)
return ma
def Media(data):
S=0
for i in range(len(data)):
S+=data[i]
media= S/len(data)
return media
def DevSTD(data):
media=Media(data)
S=0
for i in range(len(data)):
S+= (media-data[i])*(media-data[i])
S=np.sqrt(S)
devstd=S/len(data)
return devstd
#function which complete the historical series filling the missing days
def CompleteCalendar(dati):
year=[]
month=[]
day=[]
for i in range(len(dati)):
year.append(int(dati.Date[i][0:4]))
month.append(int(dati.Date[i][5:7]))
day.append(int(dati.Date[i][8:10]))
calendario=[]
for i in range(len(dati)):
calendario.append(datetime.datetime(year[i], month[i], day[i]).weekday())
for i in range(len(dati)):
vol.append(dati.Volume[i])
for i in range(len(dati)):
data.append(dati.Close[i])
index=[]
for i in range(0,len(dati)-1):
if (calendario[i]==4 and calendario[i+1]!=0):
index.append(i)
elif (calendario[i]!=(calendario[i+1]-1) and calendario[i]!=4):
index.append(i)
c=-1
for i in index:
c+=1
if (calendario[i+c]==4):
calendario.insert(i+1+c,0)
else:
calendario.insert(i+1+c,calendario[i+c]+1)
c=-1
for i in index:
c+=1
data.insert(i+1+c, data[i+c])
vol.insert(i+1+c, 0)
#settings class of XCS problem
class HaystackProblem(Scenario):
def __init__(self, p, t, input_size=10):
training_cycles=len(p)-1
self.p=p
self.t=t
self.input_size = input_size
self.possible_actions = ('Buy', 'Sell', 'Pass')
self.initial_training_cycles = training_cycles
self.remaining_cycles = training_cycles
@property
def is_dynamic(self):
return False
def get_possible_actions(self):
return self.possible_actions
def reset(self):
self.remaining_cycles = self.initial_training_cycles
def more(self):
return self.remaining_cycles > 0
def sense(self):
haystack = BitString(self.p[self.remaining_cycles])
return haystack
def execute(self, action):
self.remaining_cycles -= 1
return action == self.t[self.remaining_cycles]
#ARBITRAJEUR
class Arbitrajeur:
def __init__(self,id):
self.id=id
self.gain=0 #guadagno
self.cash=0
self.stock=0
def Action(self, data, price ):
if(data>price):
decision = 'Buy'
else:
decision ='Sell'
return decision
def PriceBuy(self, priceS):
link=[]
link.append(priceS+(priceS*0.001))
link.append(self.id)
return link
def PriceSell(self, priceB):
link=[]
link.append(priceB-(priceB*0.001))
link.append(self.id)
return link
#XCS
class XCS:
def __init__(self,id):
self.id=id
self.gain=0 #guadagno
self.cash=0
self.stock=0
def PriceBuy(self, priceS):
link=[]
link.append(priceS+0.1)
link.append(self.id)
return link
def PriceSell(self, priceB):
link=[]
link.append(priceB-0.1)
link.append(self.id)
return link
def Train(self,data, vol):
ma5=MA(data,5)
ma10=MA(data,10)
environment=[]
for i in range(10,len(data)-5):
l=[]
#prima regola
if(data[i]>=ma5[i]):
l.append('1')
else:
l.append('0')
#seconda regola
if(data[i]>=ma10[i]):
l.append('1')
else:
l.append('0')
#terza regola
if(data[i]/data[i-2]>1.02):
l.append('1')
else:
l.append('0')
#quarta regola
if(data[i]/data[i-2]<(1/1.02)):
l.append('1')
else:
l.append('0')
#quinta regola
if(ma10[i]-ma10[i-5]>0):
l.append('1')
else:
l.append('0')
#sesta regola
if(ma5[i]-ma5[i-5]<0):
l.append('1')
else:
l.append('0')
#settima regola
if(data[i]-data[i-10]>0):
l.append('1')
else:
l.append('0')
#ottava regola
if(data[i]-data[i-5]>0):
l.append('1')
else:
l.append('0')
#REGOLE SUI VOLUMI
devvol=DevSTD(vol)
volmedio=Media(vol)
if (vol[i]==0):
vol[i]=volmedio
if((vol[i]-volmedio) > devvol):
l.append('1')
else:
l.append('0')
if((volmedio-vol[i]) > devvol):
l.append('1')
else:
l.append('0')
#AZIONE
if(data[i+5]/data[i]>1.015):
l.append('Buy')
elif(data[i+5]/data[i]<1/1.015):
l.append('Sell')
else:
l.append('Pass')
environment.append(l)
p=[]
f=''
for i in range (len(environment)):
f=''
for j in range (len(environment[1])-1):
f+=environment[i][j]
p.append(f)
t=[]
for i in range (len(environment)):
t.append(environment[i][len(environment[0])-1])
problem= HaystackProblem(p,t)
scenario = ScenarioObserver(problem)
algorithm = XCSAlgorithm()
#xcs' parameters settings
algorithm.exploration_probability = .001
algorithm.ga_threshold = 100
algorithm.crossover_probability = .4
algorithm.do_action_set_subsumption = False
algorithm.do_ga_subsumption = False
algorithm.wildcard_probability = .1
algorithm.deletion_threshold = 0
algorithm.mutation_probability = .0001
model = algorithm.new_model(scenario)
model.run(scenario, learn=True)
self.model=model
#function which create the environment from the closing prices of the market
def environment(self, i, close, closevol):
ma5=MA(close,5)
ma10=MA(close,10)
l=[]
#I rule
if(close[i]>=ma5[i]):
l.append('1')
else:
l.append('0')
#II rule
if(close[i]>=ma10[i]):
l.append('1')
else:
l.append('0')
#III rule
if(close[i]/close[i-2]>1.02):
l.append('1')
else:
l.append('0')
#IV rule
if(close[i]/close[i-2]<(1/1.02)):
l.append('1')
else:
l.append('0')
#V rule
if(ma10[i]-ma10[i-5]>0):
l.append('1')
else:
l.append('0')
#VI rule
if(ma5[i]-ma5[i-5]<0):
l.append('1')
else:
l.append('0')
#VII rule
if(close[i]-close[i-10]>0):
l.append('1')
else:
l.append('0')
#VIII rule
if(close[i]-close[i-5]>0):
l.append('1')
else:
l.append('0')
#vuolumes' rules
devvol=DevSTD(closevol)
volmedio=Media(closevol)
if (closevol[i]==0):
closevol[i]=volmedio
if((closevol[i]-volmedio) > devvol):
l.append('1')
else:
l.append('0')
if((volmedio-closevol[i]) > devvol):
l.append('1')
else:
l.append('0')
return (l)
def Action(self,statomerc):
countS=0
countB=0
countP=0
for rule in self.model:
if (rule.fitness>0.5 and rule.experience>15):
perf=0
canc=0
for j in range (10):
if (statomerc[j]==str(rule.condition[j])):
perf+=1
if (rule.condition[j]==None):
canc+=1
if ((canc+perf)==10 and canc<9):
if(rule.action=='Buy'):
countB+=rule.fitness*rule.numerosity
elif (rule.action=='Sell'):
countS+=rule.fitness*rule.numerosity
else:
countP+=rule.fitness*rule.numerosity
if (countB==0 and countS==0 and countP==0):
countP=1
if (countB>countS and countB>countP):
return('Buy')
elif (countS>countB and countS>countP):
return('Sell')
else:
return('Pass')
#RANDOM AGENT
class RandomAgent:
def __init__(self,id):
self.id=id
self.gain=0
self.cash=0
self.stock=0
def Action(self):
decision= rd.random()
if(decision<=0.45):
decision='Buy'
elif(decision<0.9):
decision='Sell'
else:
decision='Pass'
return decision
def Price(self, price):
link=[]
link.append(float(price)+rd.gauss(0, price/100))
link.append(self.id)
return link
#reading inputs
INPUT = pd.read_csv('input.csv', sep=",")
#upload and prepare historical serie used for the xcs test
dati2 = pd.read_csv(INPUT.TestSeries[0], sep=",")
data=[]
vol=[]
CompleteCalendar(dati2)
train2=[]
for i in range(len(data)):
train2.append(data[i])
trainvol2=[]
for i in range(len(data)):
trainvol2.append(vol[i])
#upload and prepare historical serie used for xcs traning
dati = pd.read_csv(INPUT.TrainSeries[0], sep=",")
data=[]
vol=[]
CompleteCalendar(dati)
train=[]
for i in range(int(len(data)*0.7)):
train.append(data[i])
close=[]
for i in range(0,len(data)):
close.append(data[i])
trainvol=[]
for i in range(int(len(data)*0.7)):
trainvol.append(vol[i])
closevol=[]
for i in range(0,len(data)):
closevol.append(vol[i])
plt.plot(data[int(len(data)*0.7):])
#Agents creation
N_random=INPUT.RandomNumber[0]
N_arbitrajeur=INPUT.ArbitrajeurNumber[0]
N_XCS=INPUT.LCSNumber[0]
agents=[]
for i in range(N_random):
A=RandomAgent(i)
agents.append(A)
for i in range(N_arbitrajeur):
A=Arbitrajeur(i+N_random)
agents.append(A)
for i in range (N_XCS):
A=XCS(i+N_arbitrajeur+N_random)
A.Train(train2,trainvol2)
agents.insert(rd.randint(0,N_random),A)
#Market
initial_price=close[int(len(close)*0.7)]
price=initial_price
final_price=0
andamento=[]
andamento.append(initial_price)
nday=len(data)-len(train)
for k in range(int(len(data)*0.7),len(data)):
queueB=[]
queueS=[]
for i in range(len(agents)):
if(type(agents[i])==RandomAgent):
if(agents[i].Action()=='Buy'):
queueB.append(agents[i].Price(price))
queueB.sort()
elif(agents[i].Action()=='Sell'):
queueS.append(agents[i].Price(price))
queueS.sort()
if(type(agents[i])== Arbitrajeur):
if(agents[i].Action(close[k],price)== 'Buy'):
if(len(queueS)!=0):
queueB.append(agents[i].PriceBuy(queueS[0][0]))
else:
queueB.append(agents[i].PriceBuy(price))
queueB.sort()
else:
if(len(queueB)!=0):
queueS.append(agents[i].PriceSell(queueB[-1][0]))
else:
queueS.append(agents[i].PriceSell(price))
queueS.sort()
if(type(agents[i])== XCS):
if(agents[i].Action(agents[i].environment(k,close,closevol))=='Buy'):
if(len(queueS)!=0):
queueB.append(agents[i].PriceBuy(queueS[0][0]))
else:
queueB.append(agents[i].PriceBuy(price))
queueB.sort()
elif(agents[i].Action(agents[i].environment(k,close,closevol))=='Sell'):
if(len(queueB)!=0):
queueS.append(agents[i].PriceSell(queueB[-1][0]))
else:
queueS.append(agents[i].PriceSell(price))
queueS.sort()
if(len(queueB)!=0 and len(queueS)!=0):
if(queueB[-1][0]>queueS[0][0]):
for j in range(len(agents)):
if(queueB[-1][1]==agents[j].id):
agents[j].cash-=queueS[0][0]
agents[j].stock += 1
if(queueS[0][1]==agents[j].id):
agents[j].cash+=queueS[0][0]
agents[j].stock -= 1
final_price = queueS[0][0]
queueB.remove(queueB[-1])
queueS.remove(queueS[0])
price=final_price
train.append(final_price)
andamento.append(price)
for i in range(len(agents)):
agents[i].gain= agents[i].cash + (final_price * agents[i].stock)
plt.plot(andamento)
plt.xlabel('time (days)')
plt.ylabel('closing price ($)')
plt.show()
media=0
for i in range (len(agents)):
if (type(agents[i])==XCS):
print('Agent of type: '+str(type(agents[i]))+' earned: '+ str(agents[i].gain))
media+=agents[i].gain
print('In avarage the LCSs earned: '+ str(media/N_XCS))