Wavelet Transform for Filtering Financial Data in real - time.

The complete indicator-based technical analysis without magic and profanation.
Anyone who uses the history of the prices change of anyhow deals with the technical analysis. The formalized part of the technical analysis appears to be so-called "indicators". The indicator, by definition of Mr. Akelis, the creator of the popular program MetaStock, is "a mathematical calculation which is applied to the price and - or volume of the securities. The result is value which is used for expectation of the future change of the prices ".
|How to Buy|
Ask here|
F.A.Q.|
Online Help|
Babylonian does not decline to speculative operations.
He honours verdicts of a case, consigns them his life, hope and panic fear.
However he does not consider an investigation neither the confusing
laws of a case nor the movement of rotating spheres which open it to him.
Borches
There are thousand indicators which to an essence are, in fact, the same as minimal variations. They are often different only by theirs names. New "magic" indicators are created for two reasons: 1) poor knowledge of the underlying subject which can lead to the second invention; 2) the intentional profanation. The majority of indicator users accept them like the absolute and do not think of their physical meanings and properties. Moreover, popular books give the indicators such properties which they don’t have. Looking inside the indicators the curious can discover that it is nothing but elementary digital filters. Its theory and methods exists more than hundred years and they are used in engineering everywhere. For example, a simple moving average is a low frequencies filter with the finite impulse characteristic, an exponential moving average is a low frequencies filter with the infinite impulse characteristic, MACD is a band pass filter. Stochastic and CCI are the same as price normalized by different ways etc. the filtration can be prodused either in the state space like moving average or in frequency domain where one operates by Fourier transformed initial data etc. All filters have attributes such as smoothing degree of an input signal and delay degree of the smoothed signal in relation to an input signal. Classical indicators were created before computer age when the main requirement to the indicator was easy computing it “by hands", and smoothing and delay quality were estimated later. The classical indicators under these characteristics are varied from bad up to worse. For example, 200-day's moving average that popular among technical analytics delays neither much nor a little for a half of a window of averaging, or for 100 days, at very poor quality of smoothing.
From the point of view of the filtration theory oscillators are band pass filters or differentiating filters. Their physical analogue is a velocity of prices. Take a look to the popular technical analysis tool "divergence" meaning that the price and an oscillator have different directions. It is the analog of necessary extremum condition of a smooth function. It is good to emphasize that sufficient extremum condition does not follow from anywhere, i.e. extremum of a smooth function should be followed by divergence, but it does not follow from divergence that extremum is reached there. Use of this approach of the technical analysis, as well as many others, is based on a logic mistake of substitution of a sufficient condition by necessary one. The turn of the prices follows by divergence is similar to the fact that eating of cucumbers before death follows that the cucumbers are the reason of death.
The computerization and digital signal processing development let improve classical indicators essentially due to application of modern methods of information processing to prices. Indicators began to smooth better and to delay less. However Holy Grail has failed. First, the prices are non stationary, i.e. the characteristics of filters are varied during the time. Second, as different from technical problems, the kind of a signal and noise distributions for the price are unknown, i.e. nobody know what to filter actually. Third, being filtered by means of Fourier and similar methods prices change the previous values to the addition of the new data: we receive ideal trends under a history data but we can only trade them from right hand to left hand.
Fourier transformation is based on representation of initial series by the infinite sum of sinusoids with a various phase, amplitude and frequency. Recently wavelet transformations was widely adopted in various areas of data processing in which initial series are represented as the sum of some locally defined functions named wavelets. They are constructed by shifting and vertical and horizontal scaling of certain the prototype function. Wavelet transformation, in essence, is fractal that allows the effective using it in the technical analysis. First, it allows to carry out the multiscale analysis of prices, objectively identify trends on various scales by duration and amplitude, separate traders to various groups: scalpers, day traders, swing traders, position traders and long-term investors. The multiscale analysis can be interpreted as the analysis on various time frames. Second, it allows determine noise as the insufficient for reception of the profit amplitude and frequency movement of the prices that effectively allows filter the price series simply subtracting the lowest scale wavelets from it. Third, the additional filtration of white noise without delay is possible. Fourth, long-term trends are defined objectively. Fifth, wavelets do not contain optimized parameters in construct to standard indicators. Sixth, the used wavelets type is adapted to deal with the time ordered data and does not distorted on the last price values. Seventh, the used wavelet transformation is very effective computationally that allows use it in real time for the large massives of tick data. Eighth, it is effective to use wavelets as input data for neural networks and other methods of forecasting and recognition.
We use Redundant Haar wavelet transformation that represents an initial price series by the sum of the band pass filters named wavelets, and the residual low-frequency filter:
Price = + Residual,
Where N – - number of examined scales. It is necessary to say that the number of the used data values (i.e. the lookback period),on which wavelets compute is equal , therefore the greatest possible scale . 512 previous price values are more than enough for any practical problems. Waveleti i are similar to oscillators with consistently growing lookback periods while Residual term is similar to moving average. It is possible to read about Redundant Haar wavelets at http://www.multiresolution.comin more details.
The white noise filtration is made as follows. A signal or noise is defined on every scale. If noise is identified then the appropriate wavelet has zero value. If the signal is identified then the appropriate wavelet remains without change. Then we make inverse wavelet transformation and we receive the filtered signal.
Trend is determined as a significant movement on the considered scale, i.e. the signal / noise ratio for trend identification should be more than the given threshold of sensitivity. As noise is Gaussian by supposition, it is possible to apply statistical " Sigma rule " by setting a threshold in a range of 2 to 3.
The Application is realized as the dynamic library dll. The interaction with the library is carried out by means of two functions:
- RUNWVL(&ArrayPrice[0],Scales, Threshold),
that carries out the direct and inverse Redundant Haar wavelet transformations.
The given function returns the filtered price series. Input parameters for function RUNWVL are
- Data file which we shall set below,
- Number of scales
,
- Threshold value of the signal / noise ratio, as a rule.
Clearly that value of function RUNWVL(&ArrayPrice[0],Scales, 0) is the initial price series.
- GetAllValues(Output, Scale),
which values according to the parameter Output value are
- Redundant Haar wavelet coefficient (Output = 1),
- Noise level (Output = 2),
- Filtered Redundant Haar wavelet coefficient (Output = 3).
On the appropriate scale which is set by parameter Scale .
For example, GetAllValues(1, 5) is equal to the 5-th coefficient value Wavelet5. GetAllValues(Output, ) ) provides the Residual term.
To work with library dll it is necessary
- To define input values of an indicator, a signal or any another study, one has to add the following lines in the beginning of the indicator or signal code:
Inputs: Price(Close) { a price series },
Scales(8) { number of scales },
NSigma(2) { threshold value for signal / noise }; |
- To define functions dll,
defineDLLFunc: "tswvl.DLL", FLOAT, "RUNWVL",LPFLOAT,int,float;
defineDLLFunc: "tswvl.DLL", FLOAT, "GETALLVALUES",int,int; |
- To define the input file of a given lengths

vars: lookback(0), count(0);
Array: ArrayPrice[511](0);
lookback = power(2, Scales);
for count = 0 to lookback-1 begin
ArrayPrice[count] = Price[count];
end; |
- To initialize wavelet transformation:
Value1 = RUNWVL(&ArrayPrice[0],Scales, NSigma); |
- To receive output values:
Value2 = GetAllValues(1,Count); |
- To produce required operations with the received values.
Example 1. The indicator displaying a filtered price series and a residual term of wavelet transformation:

In the Figure above one can see that the wavelet filtration (the red line) deletes outliers on non-trending periods but leaves the prices on trend periods the same. Also the residual term of wavelet transformation can be used similarly to long-term moving average.
|
{********************************************************
Non-decimated Haar Wavelet Denoised & Residual Indicator
Copyright (c) Trade Smart Research Group 2002
Notes: The math is based on Multiresolution Analysis of Time Series
www.multiresolutions.com
********************************************************}
Inputs: Price(Close), {a price series}
Scales(6), { number of scales }
NSigma(2); { threshold value signal / noise}
vars: Lookback(0), count(0); { definition of variables }
Array: ArrayPrice[511](0); {definition of Array}
defineDLLFunc: "tswvl.DLL", FLOAT, "RUNWVL",LPFLOAT,int,float; {definition dll}
defineDLLFunc: "tswvl.DLL", FLOAT, "GETALLVALUES",int,int;
lookback = power(2, Scales); {calculation of quantity of elements of a Array}
for count = 0 to lookback -1 begin
ArrayPrice[count] = Price[count]; {the task of elements of Array}
end;
Value1 = RUNWVL(&ArrayPrice[0],Scales, NSigma); {the smoothed series}
Value2 = Scales + 1;
Value3 = GetAllValues(3, value2);
Plot1(value1, "Denoised"); {drawing of charts}
Plot2(value3, "Residual");
|
Example 2. The function that provides the detrended price series, i.e. the price without long-term trend component. Obviously, it is nothing but the sum of wavelet coefficients.

It is possible to considerably improve standard oscillators using the detrended price instead of initial price. Here standard indicator RSI and the same indicator (a yellow line on the diagram) based on the TS_Wvl_DetrendPrice function are given. One can see that the modified indicator is smoother and catches the prices extrema much better then initial one.
|
{********************************************************
Non-decimated Haar Wavelet Detrended & Denoised Price Function
Copyright (c) Trade Smart Research Group 2002
Notes: The math is based on Multiresolution Analysis of Time Series
www.multiresolutions.com
********************************************************}
Inputs: Price(NumericSeries), {a price series}
Scales(Numeric), {number of scales <=9 }
NSigma(Numeric); {threshold value signal / noise}
vars: Lookback(0), count(0); {definition of variables}
Array: ArrayPrice[511](0); {definition of Array}
defineDLLFunc: "tswvl.DLL", FLOAT, "RUNWVL",LPFLOAT,int,float; {definition dll}
defineDLLFunc: "tswvl.DLL", FLOAT, "GETALLVALUES",int,int;
lookback = power(2, Scales); {calculation of quantity of elements of Array}
for count = 0 to lookback -1 begin {the task of elements of Array}
ArrayPrice[count] = Price[count];
end;
Value1 = RUNWVL(&ArrayPrice[0],Scales, NSigma); {a call dll}
Value2 = Scales + 1;
TS_Wvl_DetrendPrice = Value1 - GetAllValues(3, value2); {function evaluation}
|
Example 3. The indicator shows the family of low-frequency filters, derived by consecutive subtraction of the filtered wavelet coefficients from the filtered price (see figure):

Two indicators, TS_Wvl Filter Family è TS_Wvl Filter Family 22 are applied there: the first builds filters from 1-st to 4-th scale and the second from 5-th to 8-th.
|
{********************************************************
Non-decimated Haar Wavelet Smoothing Indicator Family
Copyright (c) 2002 Trade Smart Research Group
Notes: The math is based on Multiresolution Analysis of time series www.multiresolutions.com
********************************************************}
Inputs: Price(MedianPrice), {a price series}
NSigma(2); {threshold value signal / noise}
vars: Lookback(0), count(0); {definition of variables}
Array: ArrayPrice[16](0); {definition of Array}
defineDLLFunc: "tswvl.DLL", FLOAT, "RUNWVL",LPFLOAT,int,float; {definition dll}
defineDLLFunc: "tswvl.DLL", FLOAT, "GETALLVALUES",int,int;
for count = 0 to 15 begin {the task of elements of Array}
ArrayPrice[count] = Price[count];
end;
Value11 = RUNWVL(&ArrayPrice[0], 4, NSigma); {call dll function}
Value1 = value11 - GetAllValues(3,1);
Value2 = value1 - GetAllValues(3,2);
Value3 = value2 - GetAllValues(3,3);
Value4 = value3 - GetAllValues(3,4);
Plot1(value1, "1"); {drawing of charts}
Plot2(value2, "2");
Plot3(value3, "3");
Plot4(value4, "4");
|
Example 4. The indicator displays consecutive wavelet coefficients, since FirstScale number:

Here wavelet coefficients of price series are given. They can be used instead of usual oscillators.
|
{********************************************************
Non-decimated Haar Wavelet Coefficients
Copyright (c) Trade Smart Research Group 2002
Notes: The math is based on Multiresolution Analysis of Time Series www.multiresolutions.com
********************************************************}
Inputs: Price(MedianPrice), { a price series }
FirstScale(4) { number of scales must be <= 6 },
NSigma(3); { threshold value signal / noise }
vars: count(0), scales(1); {definition of variables}
Array: ArrayPrice[511](0); {definition of Array}
defineDLLFunc: "tswvl.DLL", FLOAT, "RUNWVL",LPFLOAT,int,float; {definition dll}
defineDLLFunc: "tswvl.DLL", FLOAT, "GETALLVALUES",int,int;
scales = FirstScale + 4;
for count = 0 to power(2, Scales) - 1 begin {the task of elements of Array}
ArrayPrice[count] = Price[count];
end;
Value2 = RUNWVL(&ArrayPrice[0], scales, NSigma); {call dll function}
Value3 = GetAllValues(3,FirstScale);
Value4 = GetAllValues(3,FirstScale + 1);
Value5 = GetAllValues(3,FirstScale + 2);
Value6 = GetAllValues(3,FirstScale + 3);
Plot1(value3, "First"); { drawing of charts }
Plot2(value4, " First +1");
Plot3(value5, " First +2");
Plot4(value6, " First +3"); |
Example 5. ShowMe that identifies the trend on each bar on all given scales.

To apply the study to the plot, it is necessary to start TS_Wvl Trend Nowcast from menu ShowMe, to press button Expert Commentary and to click the mouse on the required bar. After that the comment window will appear. The result is shown in the figure above. The family of low-frequency filters (Example 3) and wavelet coefficients (Example 4) is applied to the plot too. It is interesting to notice that in the points where trend is not identified on several scales, the appropriate low-frequency filters coincide, but are not crossed, that allows avoid false signals whichcrossing moving averages , for example, will give there. The concurrence of filters can be treated as the indicator of the breakout mode and the avoiding to use counter trend methods.
|
{********************************************************
Non-decimated Haar Wavelet Trend Detection ShowMe
Copyright (c) Trade Smart Research Group 2002
Notes: The math is based on Multiresolution Analysis of Time Series
www.multiresolutions.com
********************************************************}
Inputs: Price(Close), {a price series}
NSigma(2); {threshold value signal / noise}
vars: Lookback(0), AllText(""), count(0); {definition of variables}
Arrays: Sigma[10](0), Wavelet[10](0), Comment[10](""); {definition of Array}
Array: ArrayPrice[511](0);
defineDLLFunc: "tswvl.DLL", FLOAT, "RUNWVL",LPFLOAT,int,float;
defineDLLFunc: "tswvl.DLL", FLOAT, "GETALLVALUES",int,int;
for count = 0 to 511 begin {the task of elements of Array}
ArrayPrice[count] = Price[count];
end;
Value1 = RUNWVL(&ArrayPrice[0], 9, NSigma); {call dll function}
AllText = "";
for count = 1 to 9 begin
Wavelet[count] = GetAllValues(1,count);
Sigma[count] = GetAllValues(2,count);
if absvalue(Wavelet[count]) < NSigma * Sigma[count] then
Comment[count] = "No detection";
if Wavelet[count] > NSigma * Sigma[count] and
absvalue(Wavelet[count][1]) < NSigma * Sigma[count][1] then
Comment[count] = "New upward detection" + " SNR = " + NumToStr(AbsValue(iff(Sigma[count] >0, Wavelet[count] / Sigma[count], 1)), 2);
if Wavelet[count] < - NSigma * Sigma[count] and
absvalue(Wavelet[count][1]) < NSigma * Sigma[count][1] then
Comment[count] = "New downward detection" + " SNR = " + NumToStr(AbsValue(iff(Sigma[count] >0, Wavelet[count] / Sigma[count], 1)), 2);
if Wavelet[count] > NSigma * Sigma[count] and Wavelet[count][1] < - NSigma * Sigma[count][1] then
Comment[count] = "Upward reversal" + " SNR = " + NumToStr(AbsValue(iff(Sigma[count] >0, Wavelet[count] / Sigma[count], 1)), 2);
if Wavelet[count] < - NSigma * Sigma[count] and Wavelet[count][1] > NSigma * Sigma[count][1] then
Comment[count] = "Downward reversal" + " SNR = " + NumToStr(AbsValue(iff(Sigma[count] >0, Wavelet[count] / Sigma[count], 1)), 2);
if Wavelet[count] > NSigma * Sigma[count] and absvalue(Wavelet[count][1]) > NSigma * Sigma[count][1] then
Comment[count] = "Positive significant structure";
if Wavelet[count] < - NSigma * Sigma[count] and absvalue(Wavelet[count][1]) > NSigma * Sigma[count][1] then
Comment[count] = "Negative significant structure";
if absvalue(Wavelet[count]) < NSigma * Sigma[count] and absvalue(Wavelet[count][1]) > NSigma * Sigma[count][1] then
Comment[count] = "End of significant structure";
AllText = AllText + "SCALE " + NumToStr(count, 0) + " " + Comment[count] + NewLine;
end;
if atCommentaryBar then
begin
CommentaryCL(AllText);
value1 = Text_New(Date, Time, L, "");
end;
|
Example 6.The indicator displaying the signal / noise ratio, since FirstScale:

One can see in a figure that the signal / noise ratio grows with increase of scale, as one would expect: on smaller scales noise prevails.
|
{********************************************************
Non-decimated Haar Wavelet Signal to Noise Ratio
Copyright (c) Trade Smart Research Group 2002
Notes: The math is based on Multiresolution Analysis of Time Series
www.multiresolutions.com
********************************************************}
Inputs: Price(MedianPrice), {a price series}
FirstScale(1); {the first scale from which indicators are drawn}
vars: scales(0), count(0);
Array: ArrayPrice[511](0);
defineDLLFunc: "tswvl.DLL", FLOAT, "RUNWVL",LPFLOAT,int,float; {definition dll}
defineDLLFunc: "tswvl.DLL", FLOAT, "GETALLVALUES",int,int;
for count = 0 to 511 begin {the task of elements of Array}
ArrayPrice[count] = Price[count];
end;
value1 = FirstScale + 3;
Value2 = RUNWVL(&ArrayPrice[0],value1, 3); {call dll function}
value3 = GetAllValues(2,FirstScale);
value4 = GetAllValues(2,FirstScale + 1);
value5 = GetAllValues(2,FirstScale + 2);
value6 = GetAllValues(2,FirstScale + 3);
if value3 > 0 then Value7 = AbsValue(GetAllValues(1,FirstScale))/value3 else value7 = 0;
if value4 > 0 then Value8 = AbsValue(GetAllValues(1,FirstScale + 1))/value4 else value8 = 0;
if value5 > 0 then Value9 = AbsValue(GetAllValues(1,FirstScale + 2))/value5 else value9 = 0;
if value6 > 0 then Value10 = AbsValue(GetAllValues(1,FirstScale + 3))/value6 else value10 = 0;
if FirstScale > 4 then begin
SetPlotColor(1, 13);
SetPlotColor(2, 9);
SetPlotColor(3, 14);
SetPlotColor(4, 10);
end;
Plot1(value7, "First"); {drawing of charts}
Plot2(value8, "First +1");
Plot3(value9, "First +2");
Plot4(value10, "First +3");
|
Example 7.A signal opens positions if wavelet coefficients have identical directions, and closing positions if they have different directions:

This elementary strategy is profitable on all range of scales. The report is obtained at default values of parameters, without any optimization.
|
{********************************************************
Non-decimated Haar Wavelet Slope signal
Copyright (c) Trade Smart Research Group 2002
Notes: The math is based on Multiresolution Analysis of Time Series
www.multiresolutions.com
********************************************************}
Inputs: EntryScale(6), {scale Wavelet for an input(entrance)}
ExitScale(5); {scale âåéâëåòà for an output(exit)}
vars: Lookback(0), Scales(0), EntryWL(0), ExitWL(0), Count(0);
Array: ArrayPrice[511](0);
defineDLLFunc: "tswvl.DLL", FLOAT, "RUNWVL",LPFLOAT,int,float; { definition dll }
defineDLLFunc: "tswvl.DLL", FLOAT, "GETALLVALUES",int,int;
Scales = maxlist(EntryScale, ExitScale);
lookback = power(2, Scales);
for count = 0 to lookback-1 begin
ArrayPrice[count] = Close[count];
end;
Value1 = RUNWVL(&ArrayPrice[0],Scales, 0); {call dll function}
EntryWL = GetAllValues(3,EntryScale);
ExitWL = GetAllValues(3,ExitScale);
Condition1 = EntryWL > EntryWL[1];
Condition2 = ExitWL > ExitWL[1];
If Condition1 = True and Condition2 = True Then
Buy("Slope.LE") at close;
If Condition1 = False and Condition2 = False Then
Sell("Slope.SE") at close;
If Condition2 = False Then
ExitLong("Slope.LX") at close;
If Condition2 = True Then
ExitShort("Slope.SX") at close;
|
Example 8. . The signal that opens positions if trend is identified on the given scale, and closing them if the end of trend is fond.

Here is the report of the non-optimized system. It shows remarkable robustness concerning the parameter NSigma from "theoretically proved" range 2-3 that corresponds 95-99 % of Gaussian noise amplitude. The concrete scale is expedient for choosing from the middle of scales, from the third to the fifth.
|
{********************************************************
Non-decimated Haar Wavelet Trend Nowcast Signal
Copyright (c) Trade Smart Research Group 2002
Notes: The math is based on Multiresolution Analysis of Time Series
www.multiresolutions.com
********************************************************}
Inputs: Scale(5), {wavelet scale}
NSigma(3); {threshold value signal / noise}
vars: Wavelet(0), Sigma(0), Trend(0), countarray(0), num(1);
Array: ArrayPrice[511](0);
defineDLLFunc: "tswvl.DLL", FLOAT, "RUNWVL",LPFLOAT,int,float;
defineDLLFunc: "tswvl.DLL", FLOAT, "GETALLVALUES",int,int;
for countarray = 0 to 255 begin
ArrayPrice[countarray] = Close[countarray];
end;
Value1 = RUNWVL(&ArrayPrice[0], 8, NSigma);
Wavelet = GetAllValues(1, Scale);
Sigma = GetAllValues(2, Scale);
if Wavelet > NSigma * Sigma then Trend = 1
else
if Wavelet < - NSigma * Sigma then Trend = -1
else
Trend = 0;
if Trend = 1 then buy("NCast.LE") num contracts at close;
if Trend = -1 then sell("NCast.SE") num contracts at close;
if Trend = 0 and marketposition = 1 then ExitLong("NCast.LX") at close;
if Trend = 0 and marketposition = -1 then ExitShort("NCast.SX") at close;
|
Example 9.. A signal opens a long position if the "fast" low-frequency filter constructed in example 3, rises above the "slow" filter, and opens a short position if the "fast" filter falls below "slow" filter.

Notice, that wavelet based low-frequency filters use data points. Compare the results of the given system to the crossover of moving averages of the same lengths. The top report is the wavelet filters crossover, parameters by default, without optimization.
Results of application of the same strategy - moving average crossover by length and , instead of wavelet filters on the same data are resulted below:

Comments are unnecessary in this case.
Do not pay attention to the identical name of strategy: we have replaced last two lines in initial code EasyLenguage with that are bracketed for the simplicity.
|
{********************************************************
Non-decimated Haar Wavelet Filter Crossover system
Copyright (c) Trade Smart Research Group 2002
Notes: The math is based on Multiresolution Analysis of Time Series
www.multiresolutions.com
********************************************************}
Inputs: MinScale(2), {the minimal wavelet scale }
MaxScale(4), {the maximal wavelet scale }
NSigma(3); {threshold value signal / noise}
vars: Lookback(0), Count(0);
Array: Filter[9](close);
Array: ArrayPrice[511](0);
defineDLLFunc: "tswvl.DLL", FLOAT, "RUNWVL",LPFLOAT,int,float;
defineDLLFunc: "tswvl.DLL", FLOAT, "GETALLVALUES",int,int;
Lookback = Power(2, MaxScale);
for count = 0 to lookback-1 begin
ArrayPrice[count] = Close[count];
end;
Filter[0] = RUNWVL(&ArrayPrice[0], MaxScale, NSigma);
for count = 1 to MaxScale begin
Filter[count] = Filter[count - 1] - GetAllValues(3,count);
end;
if Filter[MinScale] cross above Filter[MaxScale] Then Buy("Cross.LE") at close;
if Filter[MinScale] cross below Filter[MaxScale] Then Sell("Cross.SE") at close;
{
value21 = power(2, MinScale);
value22 = power(2, MaxScale);
value11 = Average(close, value21);
value12 = Average(close, value22);
if value11 cross above value12 Then Buy("Cross.LE") at close;
if value11 cross below value12 Then Sell("Cross.SE") at close;
}
|
These elementary examples evidently show that modern computer methods can improve an arsenal of technical analytics.
|How to Buy|
Ask here|
F.A.Q.|
Online Help|
Copyright © TS Research Group 2002, e-mail: info@tsresearchgroup.com. Developed by webdesign.tria.lv |