Archive for stocks

Artificial intelligence in trading: k-means clustering

There is many flavors of artificial intelligence (AI), however I want to show practical example of the cluster analysis. It is very applicable in finance. For example, one of stylized facts of volatility is, that it moves in clusters, meaning that today’s volatility will be more likely as yesterday’s volatility. To gauge these moves you can use hidden Markov chain (complicated method) or k-means (probably to simplified). However, GARCH model successfully exploits this stylized fact to make prediction of tomorrow’s volatility (it takes into account another fact as well – volatility is mean reverting process).

K-means is based on unsupervised learning – you give the data and k-means decides how to classify it. The idea is to split data into clusters based on cluster center and assign each point to nearest center.  There is drawback with such approach – the algorithm tries to establish the centers of  clusters with initial data set. If the data is very noisy and the centers are not stable, then every try will give you different results.

As you probably know, the distribution of financial data is very unstable. How to tackle this problem? We should be looking at daily returns instead of prices. The figure below shows daily returns of SPY stock.

?View Code RSPLUS
setwd('/home/git/Rproject/kmeans/')
require(quantmod)
require(ggplot2)
Sys.setenv(TZ="GMT")
getSymbols('SPY',from='2000-01-01')
 
x=data.frame(d=index(Cl(SPY)),return=as.numeric(Delt(Cl(SPY))))
png('daily_density.png',width=500)
ggplot(x,aes(return))+stat_density(colour="steelblue", size=2, fill=NA)+xlab(label='Daily returns')
dev.off()

Photobucket

I was ready to show another trick – how to neutralize long tails by replacing existing distribution with uniform distribution, but quick test revealed, that this leads to uninterpretable results.

OK, lets move further – how many clusters should we have? Can AI give us a clue? Of course, but keep in mind that then your future decision will be anchored.

?View Code RSPLUS
nasa=tail(cbind(Delt(Op(SPY),Hi(SPY)),Delt(Op(SPY),Lo(SPY)),Delt(Op(SPY),Cl(SPY))),-1)
 
#optimal number of clusters
wss = (nrow(nasa)-1)*sum(apply(nasa,2,var))
for (i in 2:15) wss[i] = sum(kmeans(nasa, centers=i)$withinss)
wss=(data.frame(number=1:15,value=as.numeric(wss)))
 
png('numberOfClusters.png',width=500)
ggplot(wss,aes(number,value))+geom_point()+
  xlab("Number of Clusters")+ylab("Within groups sum of squares")+geom_smooth()
dev.off()

Photobucket

The figure above implies, that we should have more than 15 clusters for financial data. Well, for sake of simplicity and education purpose lets use only 5.

?View Code RSPLUS
kmeanObject=kmeans(nasa,5,iter.max=10)
kmeanObject$centers
autocorrelation=head(cbind(kmeanObject$cluster,lag(as.xts(kmeanObject$cluster),-1)),-1)
xtabs(~autocorrelation[,1]+(autocorrelation[,2]))
 
y=apply(xtabs(~autocorrelation[,1]+(autocorrelation[,2])),1,sum)
x=xtabs(~autocorrelation[,1]+(autocorrelation[,2]))
 
z=x
for(i in 1:5)
{
  z[i,]=(x[i,]/y[i])
}

The code above actually shows, how to run k-means clustering in R. The first line runs the sorting and the second shows clusters’ centroids:

High Low Close
1 0.0388 -0.0094 0.0313
2 0.0049 -0.0050 0.0006
3 0.0143 -0.0038 0.0106
4 0.0038 -0.0148 -0.0103
5 0.0053 -0.0348 -0.0280

So, we have 5 clusters: 1. extremely positive day, 2. flat day, 3. positive day and 4,5 are clusters with negative outcome.
The third and fourth lines in the code above checks and prints autocorrelation between today(N0) and tomorrow(N1):

1 2 3 4 5
1 11 24 29 21 12
2 16 991 288 351 42
3 17 338 144 168 28
4 27 310 202 207 32
5 26 24 33 31 23

If you prefer percentages instead of plain numbers, the following table gives you that:

1 2 3 4 5
1 0.11 0.25 0.30 0.22 0.12
2 0.01 0.59 0.17 0.21 0.02
3 0.02 0.49 0.21 0.24 0.04
4 0.03 0.40 0.26 0.27 0.04
5 0.19 0.18 0.24 0.23 0.17

How to read such tables? Lets take for example line 2. The first table says, that the centers of the cluster are following: 0.0049;-0.0050;0.0006, meaning that during such day, the price of the asset is moving in very narrow range. Now, the table 2 or 3 shows, what are the chances for the next day (N1). Here is only 1 % chance, that following day will be extremely negative or positive (1 and 5 columns), 59 % chance, that it will be as today (N0) or it will be mild volatility with positive or negative outcome (3 and 4 columns). Put it shortly – if volatility today is very low, then most likely it will be tomorrow.

For further research I would advise to increase the number of clusters and check what are the results. On the same vein IntelligentTradingTech made a post while back.

The source code can be found here.

Comments (4)

Correlation network

I came up with an idea to draw correlation network to get a grasp about relationship between a list of stocks. An alternative way to show correlation matrix would be head map, which can have limitations with big matrices (>100).
Unfortunately,  ggplot2 package doesn’t have a easy way to draw the networks, so I was left with igraph or network. I tried both, but somehow chose igraph. If you want to master either package I highly recommend to start from theoretical part – it is very well written and it will save your time trying to understand the package’s conception.

Here is correlation matrix of stocks, which correlation coef. is more than 0.5:
correlation_network

?View Code RSPLUS
require(xts)
require(quantmod)
require(igraph)
cor_mat<- matrix( runif(100), nr=10 )
cor_mat[ lower.tri(cor_mat, diag=TRUE) ]<- 0
cor_mat[ abs(cor_mat) < 0.5]<- 0
 
graph <- graph.adjacency(cor_mat>0.5, weighted=TRUE, mode="upper")
E(graph)$weight<-t(cor_mat)[abs(t(cor_mat))>0.5]
E(graph)[ weight>0.7 ]$color <- "black" E(graph)[ weight>=0.65 &amp; weight<0.7 ]$color <- "red" E(graph)[ weight>=0.6 &amp;weight<0.65 ]$color <- "green" E(graph)[ weight>=0.55 &amp;weight<0.6 ]$color <- "blue"
E(graph)[ weight<0.55  ]$color <- "yellow"
V(graph)$label<- seq(1:10)#V(graph)$name
graph$layout <- layout.fruchterman.reingold
factor<-as.factor(cut(E(graph)$weight*10,c(4,5,6,7,8),labels=c(1,10,20,30))) png('corr_network.png',width=500) plot(decompose.graph(graph)[[which.max(sapply(decompose.graph(graph), vcount))]],edge.width =as.numeric(factor)*1.5,frame=T) legend("bottomleft", title="Colors", cex=0.75, pch=16, col=c("black", "blue","red", "green","pink"), legend=c(">70%", "65-70","60-65","55-60","50-55"), ncol=2)
dev.off()

The code can be found on github.

Comments (10)

Tick data retrieval

I just published Java based code to pull tick data from Interactive Brokers. There are thousands tools to get tick data from IB, but I had one feature in mind.

You can get maximum 50 quotes per second from Interactive Brokers (its IB limitation for TWS API) . Imagine a situation, when there is a delay in swapping incoming information, because I\O process is very slow or a short overload of the system. In such case either some piece of data will be lost or the system will crash. OK, let’s say you have plenty of RAM and speedy hard drive. Does it make sense for real time trading system to write tick data into disk and then pass all information further? Can it be done asynchronous? Yes and Java Message Service was build for that.

So, my idea was to build a tool, which would grab the tick data from provider and pass it to JMS. Retrieval tool doesn’t care what happens next – disk crash, heavy processing of the data or save on the storage. On the other end – JMS can have one or many clients and it will pass all incoming information. If something happens to a client during the transfer of the information – JMS will take care of it – it will wait for fallen clients by preserving incoming information.

If you are looking for how to stick together JMS, ActiveMQ, Spring, Hibernate, JPA and Maven, then this code can help you as well.

Comments (2)

3 weak days in a row

Recently, Trading the odds posted one of many flavors of mean reverting strategies and I decided to get my hands dirty by writing R code and testing it.

You can find full description of the strategy by following latter link above. Long story short – if SPY shows lower open, high and close 3 days in a row, then buy on the close of third day and sell it 1 days later.
Let’s do simple test:

?View Code RSPLUS
require('xts')
require('quantmod')
getSymbols('SPY',from='1995-01-01',index.class=c("POSIXt","POSIXct"))
dividends=getDividends('SPY',from='1995-01-01',index.class=c("POSIXt","POSIXct"))
 
temp=cbind(dividends,SPY)
temp[,1][is.na(temp[,1])]=0
 
SPY=cbind(temp[,2],temp[,3],temp[,4],temp[,1]+temp[,5])
colnames(SPY)=c("Open","High","Low","Close")
 
#one day before
lag1=lag((SPY),1)
 
#two days defore
lag2=lag((SPY),2)
 
signal=ifelse( (Cl(lag2)>Cl(lag1) & Cl(lag1)>Cl(SPY))&
			(Hi(lag2)>Hi(lag1) & Hi(lag1)>Hi(SPY)) &
			(Op(lag2)>Op(lag1) & Op(lag1)>Op(SPY)),
			1,0
)
#one day later
lag3=lag(Cl(SPY),-1)
 
profit=(lag3/Cl(SPY)-1)*signal
profit[is.na(profit)]=0
png(file='first.png',width=500)
plot(cumprod(profit+1),main='Profit 1995-2010')
dev.off()

The code above supposed to produce something similar:

Photobucket

Nice curve, isn’t it? But neither commissions nor slippage were taken into account. So, let’s run more complicated test. For that purpose I utilized blotter package. Here’s the code:

?View Code RSPLUS
require('xts')
require('quantmod')
require('blotter')
require('PerformanceAnalytics')
require('FinancialInstrument')
getSymbols('SPY',from='1995-01-01',index.class=c("POSIXt","POSIXct"))
dividends=getDividends('SPY',from='1995-01-01',index.class=c("POSIXt","POSIXct"))
 
temp=cbind(dividends,SPY)
temp[,1][is.na(temp[,1])]=0
 
SPY=cbind(temp[,2],temp[,3],temp[,4],temp[,1]+temp[,5])
colnames(SPY)=c('Open','High','Low','Close')
 
#one day before
lag1=lag((SPY),1)
 
#two days defore
lag2=lag((SPY),2)
 
signal=ifelse( (Cl(lag2)>Cl(lag1) & Cl(lag1)>Cl(SPY))&
			(Hi(lag2)>Hi(lag1) & Hi(lag1)>Hi(SPY)) &
			(Op(lag2)>Op(lag1) & Op(lag1)>Op(SPY)),
			1,0
)
#one day later
lag3=lag(Cl(SPY),-1)
 
symbols=c('SPY')
 
initDate=index(get(symbols)[1])
initEq=10000
rm(list=ls(envir=.blotter),envir=.blotter)
ltportfolio='3days'
ltaccount='3days'
initPortf(ltportfolio,symbols, initDate=initDate)
initAcct(ltaccount,portfolios=c(ltportfolio), initDate=initDate,initEq=initEq)
currency("USD")
stock("SPY",currency="USD",multiplier=1)
 
signal[is.na(signal)]=0
 
counter<-0
 
for(i in 2:length(signal))
{
	currentDate= time(signal)[i]
	equity = 10000 #getEndEq(ltaccount, currentDate)
	#print(paste("equity ",equity))
	position = getPosQty(ltportfolio, Symbol=symbols[1], Date=currentDate)	
	print(currentDate)
	if(position==0)
	{		
		#open a new position if signal is >0
		if(signal[i]>0 &counter ==0)
		{
			print('open position')
			closePrice<-as.double(Cl(SPY[currentDate]))
			unitSize = as.numeric(trunc((equity/closePrice)))
			commssions=-unitSize*closePrice*0.0003
			addTxn(ltportfolio, Symbol=symbols[1],  TxnDate=currentDate, TxnPrice=closePrice, TxnQty = unitSize , TxnFees=commssions, verbose=T)
			counter<-1
		}
 
	}
	else
	{
		#position is open. If signal is 0 - close it.
		if(position>0 &counter>=1)
		{
			print('close position>>>>')
			position = getPosQty(ltportfolio, Symbol=symbols[1], Date=currentDate)
			closePrice<-as.double((Cl(SPY[currentDate])))#as.double(get(symbols[1])[i+100])
			commssions=-position*closePrice*0.0003
			addTxn(ltportfolio, Symbol=symbols[1],  TxnDate=currentDate, TxnPrice=closePrice, TxnQty = -position , TxnFees=commssions, verbose=T)
			counter<-0
		}
		else
			counter<-counter+1
	}	
	#print(equity)
	updatePortf(ltportfolio, Dates = currentDate)
	updateAcct(ltaccount, Dates = currentDate)
	updateEndEq(ltaccount, Dates = currentDate)
 
	#equity = getEndEq(ltaccount, currentDate)
	#print(paste("equity ",equity))
}
result=rez1$symbols$SPY$txn[,7]
result=result[result!=0]
 
png(file='second.png',width=500)
#fix commission rate 2*3
plot(cumsum(result-6))
#next line will allow you to compare the performace with and without commissions
#chart.CumReturns(cbind((result)/10000,(result-6)/10000))
dev.off()

Photobucket

Nice curve, but let’s look beyond that. First of all, here’s nice function in PerformanceAnalytics package, AnnulizedReturns:
table.AnnualizedReturns((result-6)/10000)
Gross.Txn.Realized.PL
Annualized Return 0.0265
Annualized Std Dev 0.0494
Annualized Sharpe (Rf=0%) 0.5366

Well, Sharpe ratio is not impressive. The profit percentage of this strategy is 57% and mean of profitable return is 111$ against 98$ loss. Profit factor is ~1.55.

I think, this strategy can be as one of the parameter or vote in another system, but alone it is weak.

Comments (6)

Intraday volatility of OMX Baltic stocks

Usually, intraday volatility exhibits a “smile” – it is high at open and close and it is lower during the trading day.

DJI index, 5 min. intervals, CET time:

Photobucket

MOS stock, 5 s. intervals, CET time:

Photobucket

Because many readers of this blog are trading Nasdaq OMX Baltic stocks, it is worth to share my findings about volatility in these markets. It was surprising for me, that none of the stocks in OMX Baltic markets follow “smile” pattern as it was show above.
Read the rest of this entry »

Comments

Tyrimas: investicija į top3 akcijas vienai savaitei

Ar tam tikrą periodą pirmavusios akcijos duodą didesnę grąžą ateinančią savaitę? Tarkime, kad numatėme investuoti į šias akcijas:

TEO1L, RST1L, IVL1L, APG1L, SRS1L, UKB1L, SAN1L, SAB1L, LDJ1L, SNG1L, PTR1L, LFO1L

Pirmas variantas – lygiomis dalimis suformuoti portfelį ir suinvestuoti visą tam skirtą kapitalą. Kitas variantas – kiekvieną savaitę keisti portfelio sudėtį, perkant tik tas akcijas, kurios per X dienų skaičių turėjo didžiausią grąžą. Šiame tyrime buvo naudotos 126 darbo dienas. Perkamos tik 3, didžiausią grąžą davusios akcijos.
Atliekant tyrimą, buvo pridėta dar viena taisyklė. Jei per pasirinktą periodą visų akcijų grąža buvo neigiama, tai investicija savaitei atidedama. Pateiktame grafike – juoda linija, o žalia linija – ta pati strategija, bet investuota nepriklausant nuo to, ar grąža buvo neigiama ar teigiama.
Palyginimui sudariau indeksą iš aksčiau paminėtų akcijų – raudona linija. Mėlyna linija rodo grąža strategijos, kuri paremta slankiaisiais vidurkiais 50/200.

Photobucket

Rezultatai

Iš pirmo žvilgsnio atrodo, kad strategija tikrai gerai veikia – juodos linijos grąža yra didžiausia. Jei ši strategija sukuria kokią nors vertę, tai tada investuojant visą laiką (žalia linija), nepaisant akcijų biržos ciklo, turėtų duoti didesnę grąžą nei indeksas(raudona linija). Kaip matosi iš pateikto grafiko, investuojant kiekvieną savaitę, strategija dažniausiai atsilieka nuo indekso. Viena iš priežasčių – komisiniai mokesčiai. Dėl dažno pirkimo/pardavimo susidaro nemažos išlaidos, todėl verta pasitikrinti savo brokerio įkainius.
Į tyrimą įtraukiau slankiaisiais vidurkiais paremtą strategiją (mėlyna linija), kad galima būtų palyginti kokią papildomą grąžą duoda saugiklis, jei investuojama tik kai praeities rezultatai yra teigiami. Nors grafike mėlyna linija stipriai atsilieka nuo juodos, tačiau verta pažiūrėti koks buvo rizikos ir kokia grąžos santykis  naudojant šią strategiją.

Strategija>0   indeksas    allTheTime    GoldenCross
Annualized Return     0.39         0.15              0.06               0.19
Annualized Std          0.36         0.31                0.4               0.19
Annualized Sharpe    1.08 0.49               0.14              1.01

Žymiai paprastesnė (slankiųjų vidurkių) strategija rodo labai panašų Sharpe ratio (grąža buvo mažesnė, bet svyravimai buvo mažesni), trumpesnį laiką buvo investuota – pinigai galėjo būti investuoti į indėlį. Teisybės vardan reikia paminėti, kad pastarajai strategijai komisinio mokesčio nepaskaičiavau.
Kitas klausimas – ar tikrai kiekvieną penktadienį esate pasiruošęs skaičiuoti ir ieškoti kas davė didžiausią grąžą per tam tikrą laikotarpį?

Pastaba: bid/ask ir komisiniai į skaičiavimus nebuvo įtraukti. Dėl pirmo – gali būti rimtų nukrypimų, jei akcijos kaina yra mažesnė nei 1 lt. Dėl komisinių – jie nebuvo įtraukti nei į indekso skaičiavimą nei į strategijos rezultatų skaičiavimą.

Comments (7)

Keičiasi indeksų sudėtis

http://vz.lt/rss/straipsnis/2009/12/18/Birza_keicia_indeksu_OMX_Baltic_Benchmark_ir_OMX_Bal2

Įtariu, kad niekas nebandė aiškintis, kaip akcijos grąžą ir apyvartą įtakoja akcijos įtaukimas į OMX indeksus. Tuo tarpu JAV gerai žinomas faktas, kad įtraukus akciją į S&P500 indeksą, apyvarta, kainos svyravimai? ir kaina išauga. Priežastis paprasta – indeksą atkartojantys fondai, pensijų fondai ir pan., privalo užsipirkti naujokų akcijų, o nurašytas-parduoti.

Klausimas – o kaip su OMX indeksais? Atsakymas – logiškiausiai būtų palaukti dar 10 metų, nes indekso gyvavimo istorija per trumpa, nėra išvestinių instrumentų, kurie atkartotų indeksą (nepasant to, kad prieš porą metų, su fanfarais buvo pristatyti tiek ateities sandoriai tiek pasirinkimo sandoriai, kurie mažmeninėje prekyboje tikriausiai neegzistuoja). Taip pat neturime nei vieno pasyvaus investicinio fondo, kuris atkartotų indekso grąžą (Lietuvoje tikriausiai visi yra finansų specialistai ir visi gali uždirbti didesnę grąžą nei pasyvus investicinis fondas…).

Comments (4)

Kaip elgiasi Baltijos biržos?

Pirmi du grafikai rodo kokia suminė grąža būtų, jei investuojama būtų tik tam tikrom savaitės dienom.
Parodžiau šiuos grafikus kaimelio investuotojams – nušvilpė. Klausia jie manęs – tai ką šitie grafikai rodo? Tikrai ne daug:)

OMXV

Photobucket

OMXT

Photobucket

Kadangi darbuojuosi “mean reverting” strategijų, nutariau pažiūrėti, o kaip elgiasi indeksas, jei tris dienas iš eilės kilo? Grąža yra paskaičiuota, jei būtų investuojama į indeksą nuo vienos iki penkių dienų.
OMXV

Photobucket

OMXT

Photobucket

Upst, rezultatai tikrai nustebino, nes tikėjausi, kad suminė grąža bus neigiama arba atsitiktinė.

Pastaba geek’ams – grąžą “nutrendinau” su log() paskutiniuose dviejuose grafikuose, kad trendas neįtakotų  rezultatų;)

Comments (6)

Ar egzistuoja koreliacija tarp S&P500 ir Batijos biržų?

Man to nustatyti nepavyko, nes OMXBB indeksas turi tik dienos uždarymo kainas. Uždarymo kainos netinka, nes OMXBB biržos užsidaro dar prieš JAV biržų atidarymą.
Sprendimas – pažiūrėti kaip į S&P500 indeksą reaguoja Lietuvos Telekomas. Naudojau TEO1L dienos atidarymo kainas, kurias vėliau, viena diena pavėlinau (lag(Open,-1)), S&P500 dienos uždarymo kainos.

Kagi, turi ganėtinai didelę koreliaciją, svyruojančią tarp 0.7 ir 0.9. Koreliacijos grafikas:

Photobucket

Comments (8)

Strategija: akcijos su dideliu vid. nuokrypiu (SD) prieš akcijas su mažu SD

Pirmas klausimas, kurį reikėjo išsiaiškiti – kokios akcijos OMX Baltic biržoje svyruoja labiausiai?
Reikalingus duomenis galima rasti kurmis.org – tikiuosi, rastos klaidos TKM ir ZMP akcijų kotiruotėse jau pataisytos. Apačioje pateikiu lentelę, kurioje yra kiekvienos akcijos vertės svyravimai nuo 2005 metų. Dėmesio, skaičiuojant vidutinį nuokrypį (SD) naudojau 150 dienų langą. T.y. nuo 2005 sausio 1d. atskaičiavau 150 dienų į priekį ir paskaičiavau SD. Tada, nuo sausio 2d. atskaičiavau 150 dienų į priekį ir vėl paskaičiavau SD. Vėliau, visus SD sudėjau ir gavau SD vidurkį su slenkančiu 150 dienų langu.

SAN1L 3.13
TKM1T 2.17
IVL1L 1.75
APG1L 1.61
ZMP1L 1.3
SAF1R 1.11
MRK1T 0.86
TVEAT 0.83
BLT1T 0.72
RSU1L 0.71
VLP1L 0.69
GRD1R 0.64
HAE1T 0.6
SFGAT 0.56
OEG1T 0.54
SRS1L 0.46
PZV1L 0.43
UKB1L 0.43
NRM1T 0.42
ETLAT 0.41
RST1L 0.4
LME1R 0.37
SAB1L 0.37
GRG1L 0.27
VNF1R 0.26
ARC1T 0.18
TEO1L 0.18
TAL1T 0.13
LSC1R 0.13
KNF1L 0.07
LJL1L 0.05

Kaip kurių akcijų svyravimų vidurkis nustebino – tikėjausi, kad bankinis sektorius svyruoja labiau. Reiktų atminti, kad kai kurių akcijų SD labai mažas, nes jų likvidumas irgi labai mažas, todėl prieš panaudojant gautus rezultatus, truputi “apvaliau”.

Taigi, sudariau du indeksus – akcijų, kurių vertės labai svyruoja:
‘TKM1T’, ‘IVL1L’,'APG1L’, ‘SAN1L’
ir akcijų, kurių vertės svyruoja mažai:
‘TEO1L’,'ETLAT’,'RST1L’,'SAB1L’
Vėliau sukonstravau du paprastus indeksus (labai svyruojančių ir nelabai svyruojančių verčių). Remiausi tokiais parametrais: visų akcijų svoris indekse yra vienodas, periodas nuo 2005m. Jei akcija kurią nors dieną nesikotiravo, grąžą tai dienai prilyginau nuliui.

Strategija: pirkti akcijas su dideliu SD, jei šių akcijų grąža per paskutines 10 savaičių buvo didesnė už grąžą, akcijų su mažu SD. Parduoti akcijas kai grąža, akcijų turinčių didelį SD,  per paskutines 10 savaičių yra mažesnė už gražą, akcijų su mažu SD.

Rezultatas
Raudona linija – akcijų, turinčių didelį SD, graža nuo 2005m. iki 2009 spalio mėn. Nupirkos ir išlaikytos.
Juoda linija – tai grąža aprašytos stategijos.
Photobucket

Rezultatas nėra džiuginantis – ši strategija didesnės grąžos neduoda. Bet vienas idomus faktas – galutinė grąža yra panaši, bet rezultatų svyravimai yra skirtingi. Jei investuotojas laikytų šias akcijas savo portfelyje, tai generuotų 20 % svyravimus, tuo tarpu jei investuotojas naudotų aprašytą strategiją – grąžos svyravimai sumažėtų iki 12,4%.  Jei investuotojas turi rinktis tarp dviejų produktų, kurių grąža yra panaši, racionalus sprendimas būtų rinktis tą produktą, kurio svyravimai yra mažesni.

p.s. Komisiniai į skaičiavimus neįtraukti.

Comments

Next Page »