SmartQuant Discussion

Automated Quantitative Strategy Development, SmartQuant Product Discussion and Technical Support Forums
It is currently Sun Sep 15, 2019 9:35 pm

All times are UTC + 3 hours




Post new topic Reply to topic  [ 19 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Thu Dec 04, 2008 9:49 pm 
Offline

Joined: Tue Jul 29, 2008 7:22 pm
Posts: 59
Location: Alberta, Canada
I am working on coding the HMA indicator, but have run into 2 errors that have me puzzled. I suspect I am having issues understanding how SmartQuant utilizes BarSeries and ISeries.

The 1st error I am getting is cannot convert from 'double' to 'OpenQuant.API.BarSeries' I am getting this related to the following code:

double value1 = 2 * new WMA(Input[index, BarData] , (int)(period / 2));

I am also getting the error: The best overloaded method match for 'OpenQuant.API.Indicators.WMA.WMA(OpenQuant.API.BarSeries, int)' has some invalid arguments (related to the same line as above).

So with that context my 1st question is this: Does WMA return a double value? If so, I don't understand the 1st error. The double value1 is simply trying to store the current value of 2*WMA for later use.

My second question has to do with the WMA constructor. The basic constructor is ... WMA Constructor (BarSeries, Int32), so I don't understand where the following sytnax went wrong unless WMA cannot use Input from the ISeries Interface. How does this syntax need to change to return the value of WMA to value1?

WMA(Input[index, BarData] , (int)(period / 2));

Any help is appreciated

Gratefully,

Curious1


Top
 Profile  
 
 Post subject:
PostPosted: Fri Dec 05, 2008 4:10 pm 
Offline

Joined: Wed Oct 08, 2003 1:06 pm
Posts: 833
Hi,

I guess you should do something like following:

declare WMA indicator:
Code:
class HMA : UserIndicator
{
...
   WMA wma;
...

initialize it in your indicator constructor
Code:
wma = new WMA((BarSeries)Input, (int)(period / 2));

use wma.Last when you need the last value of the indicator, like:
Code:
double value1 = 2 * wma.Last;


Regards,
Sergey.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Dec 05, 2008 6:01 pm 
Offline

Joined: Tue Jul 29, 2008 7:22 pm
Posts: 59
Location: Alberta, Canada
Thanks Baraz ...

That helped out a bunch, but it leaves me somewhat uncertain how to deal with the 3rd WMA in the HMA formula ...
The 3rd WMA run on the the result of (WMA1-WMA2) instead of (BarSeries)Input. The line that is now giving the error is :

hma = new WMA((value1 - value2), (int) Math.Sqrt(period));

I have found references to DoubleSeries in the forum, but it does not seem to be exposed in the SmartQuant API, so in SQ, so how does one take a couple of indicator values, store them, run a math function on them and then re-run that though another indicator (WMA in this case). I included the full code below so you can see what I mean. Thanks again for the help!

Code:
#region Using declarations

using System;
using System.Collections.Generic;
using System.Text;

using OpenQuant.API;
using OpenQuant.API.Plugins;
using OpenQuant.API.Indicators;

#endregion
namespace Guy.Indicators
{
/// <summary>
/// HMA conversion.
/// </summary>
public class HMA: UserIndicator
{
      private int period;
   private BarData barData;
    WMA wma1;
   WMA wma2;
   public int Period
   {
        get { return period; }
        set { period = value; }
   }
   public BarData BarData
   {
      get { return barData; }
      set { barData = value; }
   }       
   
   public HMA(ISeries series, int period, BarData barData) : base (series)
   {
      this.period = period;
      this.barData = barData;
      this.Name = "HMA, Period = " + period;   
   }
   public HMA(ISeries series, int period)
         : this(series, period, BarData.Close)
         { 
            wma1 = new WMA((BarSeries)Input, (int)(period / 2) * 2);
            wma2 = new WMA((BarSeries)Input , period);
      }
      
       
     public override double Calculate(int index)
     {     
      double hma = double.NaN;
     
      if (index >= period - 1)
      {
         double value1 = 2 * wma1.Last;
         double value2 = wma2.Last;
         hma = new WMA((value1 - value2), (int) Math.Sqrt(period));
      
         return hma;
      }
         else
         return double.NaN;
   }
}
}


Top
 Profile  
 
 Post subject:
PostPosted: Mon Dec 08, 2008 1:03 pm 
Offline

Joined: Wed Oct 08, 2003 1:06 pm
Posts: 833
Hi,

You should create a temp time series, fill it with (value1 - value2) values in the Calculate method and create a WMA from this series. Please see the following sample:

Note that there is no WMA constructor from a TimeSeries in the current OQ verision, that's why a temporary BarSeries is used instead. We will add a constructor of WMA with TimeSeries parameter in the next version.

Code:
#region Using declarations

using System;
using System.Collections.Generic;
using System.Text;

using OpenQuant.API;
using OpenQuant.API.Plugins;
using OpenQuant.API.Indicators;

#endregion
namespace Guy.Indicators
{
   /// <summary>
   /// HMA conversion.
   /// </summary>
   public class HMA: UserIndicator
   {
      private int period;
      private BarData barData;
      WMA wma1;
      WMA wma2;
      WMA diffWma;
      
      BarSeries diffSeries;
      
      public int Period
      {
         get { return period; }
         set { period = value; }
      }
      public BarData BarData
      {
         get { return barData; }
         set { barData = value; }
      }       
   
      public HMA(ISeries series, int period, BarData barData) : base (series)
      {
         this.period = period;
         this.barData = barData;
         this.Name = "HMA, Period = " + period;            
      }
      public HMA(ISeries series, int period)
         : this(series, period, BarData.Close)
      { 
         wma1 = new WMA((BarSeries)Input, (int)(period / 2) * 2);
         wma2 = new WMA((BarSeries)Input , period);
         
         diffSeries = new BarSeries();
         diffWma = new WMA(diffSeries, (int)Math.Sqrt(period));
      }
       
       
      public override double Calculate(int index)
      {     
         double hma = double.NaN;
     
         if (index >= period - 1)
         {
            double value1 = 2 * wma1.Last;
            double value2 = wma2.Last;
                        
            diffSeries.Add(
               Input.GetDateTime(index),
               value1 - value2,
               value1 - value2,
               value1 - value2,
               value1 - value2,
               0,
               0);
            
            hma = diffWma.Last;
       
            return hma;
         }
         else
            return double.NaN;
      }
   }
}


Regards,
Sergey.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Dec 08, 2008 6:47 pm 
Offline

Joined: Tue Jul 29, 2008 7:22 pm
Posts: 59
Location: Alberta, Canada
Sergey, Thanks tons! That was exactly my question. So let me just confirm that I understand what you did.
1) You added a 3rd WMA object called diffWMA
2) You added a new BarSeries object called diffSeries
3) You initialized diffSeries as a new BarSeries()
4) You initialized diffWMA using diffSeries as the BarSeries Input to the WMA indicator
5) You added data to diffSeries in double Calculate ()
using:
Input.GetDateTime(index) as the DataTime of the BarSeries diffSeries,
Value1-Value2 as the Open of the BarSeries diffSeries,
Value1-Value2 as the High of the BarSeries diffSeries,
Value1-Value2 as the Low of the BarSeries diffSeries,
Value1-Value2 as the Close of the BarSeries diffSeries,
0 as the volume and
0 as the size.
6) Lastly, you returned diffHMA as the value of hma.

Is there anything I missed?

By the way, thanks a bunch, this helped me understand how to create temporary dataSeries for use in custom indicators! Everything compiles nicely

On a different note, when I go to use this indicator in SmartQuant I get an error that shuts dowm SmartQuant. I am somewhat puzzled by this. Here are the steps I took:
1) Compiled the HMA indicator into a DLL Guy.Indicators.
2) Copied the DLL to C:\Program Files\SmartQuant Ltd\OpenQuant 2\Bin
3) Added the reference to this DLL using Tools > Options > Projects and Solutions > Build > Add References
4) Quickly added the indicator to the Simple Moving Average CrossOver Strategy that comes shipped with SQ (Just to see it on a chart) ... Code is Below after the NullReferenceException Error
5) Built Strategy (All builds fine)
6) Ran Strategy against the Daily MSFT data that comes shipped with SQ

The result is that SmartQuant stopped running and displayed the following error. Is there an error in the original indicator code genertaing this or do I need to be particular about the type of data I can run it against?

System.NullReferenceException: Object reference not set to an instance of an object.
at Guy.Indicators.HMA.Calculate(Int32 index)
at OpenQuant.API.Plugins.UserIndicator.OnInputItemAdded(Object sender, DateTimeEventArgs args)
at SmartQuant.Series.ItemAddedEventHandler.Invoke(Object sender, DateTimeEventArgs e)
at SmartQuant.Series.TimeSeries.EmitItemAdded(DateTime dateTime)
at SmartQuant.Series.BarSeries.Add(Bar bar)
at SmartQuant.Instruments.DataManager.m3LqtlyTC(Object , BarEventArgs )
at SmartQuant.Providers.ProviderManager.Xeuohd09J(Object , BarEventArgs )
at SmartQuant.Providers.BarEventHandler.Invoke(Object sender, BarEventArgs args)
at SmartQuant.Simulation.SimulationDataProvider.EhhPZB34o(IFIXInstrument , Bar )
at SmartQuant.Simulation.SimulationDataProvider.NI50mC6nD(SeriesObjectEventArgs )
at SmartQuant.Simulation.SeriesObjectEventHandler.Invoke(SeriesObjectEventArgs args)
at SmartQuant.Simulation.Simulator.Gyc3PYAH2(IDataSeries , IDataObject )
at SmartQuant.Simulation.Simulator.Z1qoPcBNY()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()


Strategy Code that generated the above error:
Code:
using System;
using System.Drawing;

using OpenQuant.API;
using OpenQuant.API.Indicators;
using Guy.Indicators;

public class MyStrategy : Strategy
{
   [Parameter("Length of SMA1", "SMA")]
   int Length1 = 3;

   [Parameter("Length of SMA2", "SMA")]
   int Length2 = 7;
   
   [Parameter("Length of HMA1", "HMA")]
   int Length3 = 7;

   [Parameter("Color of SMA1", "SMA")]
   Color Color1 = Color.Yellow;   

   [Parameter("Color of SMA2", "SMA")]
   Color Color2 = Color.LightBlue;
   
   [Parameter("Stop OCA Level", "OCA")]
   double StopOCALevel = 0.98;

   [Parameter("Limit OCA Level", "OCA")]
   double LimitOCALevel = 1.05;
   
   [Parameter("Stop Level", "Stop")]
   double StopLevel = 0.05;

   [Parameter("Stop Type", "Stop")]
   StopType StopType = StopType.Trailing;
   
   [Parameter("StopMode", "Stop")]
   StopMode StopMode = StopMode.Percent;
   
   [Parameter("CrossoverExitEnabled", "Exit")]
   bool CrossoverExitEnabled = true;
   
   [Parameter("OCA Exit Enabled", "Exit")]
   bool OCAExitEnabled = true;

   [Parameter("Stop Exit Enabled", "Exit")]
   bool StopExitEnabled = true;
   
   // this strategy uses some of the same exit methods
   // as the breakout strategy described earlier. Look
   // there for additional documentation
   // lengths and colors of the simple moving averages   
   SMA sma1;
   SMA sma2;
   HMA hma1;
      
   // only one trade is allowed at a time
   bool entryEnabled = true;   
   
   int OCACount = 0;

   // for the orders used by this strategy
   Order marketOrder,
      limitOrder,
      stopOrder;

   [Parameter("Order quantity (number of contracts to trade)")]
   double Qty = 100;

   public override void OnStrategyStart()
   {
      
      // set up the moving averages, based on closing prices
      sma1 = new SMA(Bars, Length1, Color1);
      sma2 = new SMA(Bars, Length2, Color2);
      hma1 = new HMA(Bars, Length3, BarData.Close);
      // 0 means draw both averages on the price chart
      Draw(sma1, 0);
      Draw(sma2, 0);
      Draw(hma1,0);
      
   }

   public override void OnBar(Bar bar)
   {
      // does the fast average cross over the slow average?
      // if so, time to buy long
      Cross cross = sma1.Crosses(sma2, bar);
      // we only allow one active position at a time
      if (entryEnabled)
      {
         // if price trend is moving upward, open a long
         // position using a market order, and send it in
         if (cross == Cross.Above)
         {
            marketOrder = MarketOrder(OrderSide.Buy, Qty, "Entry");            
            marketOrder.Send();
            // if one cancels all exit method is desired, we
            // also issue a limit (profit target) order, and
            // a stop loss order in case the breakout fails.
            // The OCA exit method uses a real stop loss order.
            // The Stop exit method uses a stop indicator.
            // Use either the OCA or Stop method, not both at once.
            if (OCAExitEnabled)
            {
               // create and send a profit limit order
               double profitTarget = LimitOCALevel * bar.Close;
               limitOrder = SellLimitOrder(Qty, profitTarget, "Limit OCA " + OCACount);
               limitOrder.OCAGroup = "OCA " + Instrument.Symbol + " "
                  + OCACount;               
               limitOrder.Send();
               // create and send a stop loss order
               double lossTarget = StopOCALevel * bar.Close;
               stopOrder = SellStopOrder(Qty, lossTarget, "Stop OCA " + OCACount);
               stopOrder.OCAGroup = "OCA " + Instrument.Symbol + " "
                  + OCACount;               
               stopOrder.Send();
               // bump the OCA count to make OCA group strings unique
               OCACount++;
            }
            entryEnabled = false;
         }
      }
         // else if entry is disabled on this bar, we have an open position
      else
      {
         // if we are using the crossover exit, and if the fast
         // average just crossed below the slow average, issue a
         // market order to close the existing position
         if (CrossoverExitEnabled)
            if (cross == Cross.Below)
            {
               marketOrder = MarketOrder(OrderSide.Sell, Qty, "Crossover Exit");               
               marketOrder.Send();
            }
      }
   }
   public override void OnPositionOpened()
   {
      // if we want to exit trades using the Stop method, set a
      // a trailing stop indicator when the position is
      // first opened. The stop indicator is not a stop loss
      // order that can be executed by a broker. Instead, the stop
      // just fires the OnStopExecuted event when it it triggered.
      if (StopExitEnabled)
         SetStop(StopLevel, StopType, StopMode);
   }

   public override void OnPositionClosed()
   {
      // when a position is closed, cancel the limit and stop
      // orders that might be associated with this position.
      // But only cancel if the order has not been filled or
      // not been cancelled already.
      if (OCAExitEnabled &&
         !(limitOrder.IsFilled || limitOrder.IsCancelled))
      {
         limitOrder.Cancel();
      }
      // allow entries once again, since our position is closed
      entryEnabled = true;
   }

   public override void OnStopExecuted(Stop stop)
   {
      // if our trailing stop indicator was executed,
      // issue a market sell order to close the position.
      marketOrder = MarketOrder(OrderSide.Sell, Qty, "Stop Exit");      
      marketOrder.Send();
   }
}






Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 09, 2008 3:31 pm 
Offline

Joined: Wed Oct 08, 2003 1:06 pm
Posts: 833
Hi,

Quote:
So let me just confirm that I understand what you did.
...
Is there anything I missed?

You missed nothing :wink:
Quote:
On a different note, when I go to use this indicator in SmartQuant I get an error that shuts dowm SmartQuant. I am somewhat puzzled by this.

Please find a corrected version of HMA indicator, it should work better.
Code:
/// <summary>
   /// HMA conversion.
   /// </summary>
public class HMA: UserIndicator
{
   private int period;
   private BarData barData;
   WMA wma1;
   WMA wma2;
   WMA diffWma;
       
   BarSeries diffSeries;
       
   public int Period
   {
      get { return period; }
      set { period = value; }
   }
   public BarData BarData
   {
      get { return barData; }
      set { barData = value; }
   }       
   
   public HMA(ISeries series, int period, BarData barData) : base (series)
   {
      this.period = period;
      this.barData = barData;
      this.Name = "HMA, Period = " + period;
      
      wma1 = new WMA((BarSeries)Input, (int)(period / 2) * 2);
      wma2 = new WMA((BarSeries)Input , period);
         
      diffSeries = new BarSeries();
      diffWma = new WMA(diffSeries, (int)Math.Sqrt(period));
   
   }
   public HMA(ISeries series, int period)
      : this(series, period, BarData.Close)
   { 
   }
       
       
   public override double Calculate(int index)
   {     
      if (wma1.Count == 0 || wma2.Count == 0)
         return double.NaN;
      
      double hma = double.NaN;       
      
      if (index > period - 1)
      {
         double value1 = 2 * wma1.Last;
         double value2 = wma2.Last;
                         
         diffSeries.Add(
            Input.GetDateTime(index),
            value1 - value2,
            value1 - value2,
            value1 - value2,
            value1 - value2,
            0,
            0);
             
         if (diffWma.Count == 0)
            return double.NaN;
         
         hma = diffWma.Last;
       
         return hma;
      }
      else
         return double.NaN;
   }
}


Regards,
Sergey.


Top
 Profile  
 
PostPosted: Tue Dec 09, 2008 10:11 pm 
Offline

Joined: Tue Jul 29, 2008 7:22 pm
Posts: 59
Location: Alberta, Canada
Thanks again Baraz ... everything works nicely. I am still finding my way around the SQ API and accessing data / other indicators is still confusing me a bit. So, at the risk of beating a dead horse to death ... please bear with me as I think trough the changes you made:

1) You moved wma1, wma2, diffSeries, and diffWma into the section of code that identifies the properties for HMA. Question: Just so I understand, am I right in assuming that this section is initializing the properties of HMA and wma1, wma2, diffSeries and diffWma?

2) You left the next section blank (public HMA(ISeries series, int period)
: this(series, period, BarData.Close). Question: Also to further my understanding, am I right in assuming that this section is now identify the data series that ISeries will use to run HMA?

3) You added "if (wma1.Count == 0 || wma2.Count == 0) return double.NaN;" so that wma1 and wma2 do not try to run on the first bar of the series that contains no data yet (which is the event that created the NullReference error). Is this the case?

4) You added "if (diffWma.Count == 0) return double.NaN;". Was this nescessary because the next statement "hma = diffWma.last;" was only being run if (index > period - 1)?

Thanks for the help in understanding the changes and the purpose of those changes!

Gratefully Curious1


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 10, 2008 12:01 pm 
Offline

Joined: Wed Oct 08, 2003 1:06 pm
Posts: 833
Hi,

1) Generally I moved all initializations to one place. The problem was that you use HMA constructor with BarData parameter, so the body of constructor public HMA(ISeries series, int period) was never executed.

2) the only goal of public HMA(ISeries series, int period) constructor is to give you a possiblity to create an HMA indicator without specifying BarData parameter, like hma = new HMA(Bars, 14); instead of hma = new HMA(Bars, 14, BarData.Close)

3), 4) yes you right - checking the count prevents us from taking last value of an empty series, that leads to OutOfRangeException. The only thing that the NullReference exception was caused by the fact that the body of constructor public HMA(ISeries series, int period) was never executed.

Regards,
Sergey.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 10, 2008 5:17 pm 
Offline

Joined: Tue Jul 29, 2008 7:22 pm
Posts: 59
Location: Alberta, Canada
Thanks Sergey ... That helps me clarify things.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 12, 2009 7:32 pm 
Offline

Joined: Wed Mar 11, 2009 9:54 pm
Posts: 63
Hello,

I am new to OQ. In NinjaTrader I have avoided the double to BarSeries conversion problem by using a Set method :
double x = 5;
double y = 3;
x.Set(x-y);

I have already spent a few days and can not figure out how to do this in OQ.

Please help
Thank you.

_________________
xtrender


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 12, 2009 8:08 pm 
Offline

Joined: Wed Mar 11, 2009 9:54 pm
Posts: 63
Perhaps I should clarify what exactly the problem is:

double Cmp = MOM1.Last + SMA1.Last;//this line compiles

SMA2 = new SMA(Cmp, SMALength);//This gives the same message as I would get in NinjaTrader : The best overloaded method..has invalid arguments and cannot convert from double oo OQ.API.BarSeries.

Well I understand the problem, namely SMA takes BarSeries as first argument, but don't see the solution...

It took me some time to work around this problem in NinjaTrader, I am not sure I would like to dothis the hard way again.

This is the most genereral question related to data type conversion and should be properly documented as I am sure this one will be asked time and time again

Thank you.

_________________
xtrender


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 12, 2009 11:46 pm 
Offline

Joined: Tue Jul 29, 2008 7:22 pm
Posts: 59
Location: Alberta, Canada
Hi xTrender ... Welcome to SmartQuant. I also came here from NT, so I understand your challenge. NT uses a vairiation of C# that "automates" the building of some things with 'ninjaScipt". SmartQuant does not and simply uses raw C#. if you aren't a programmer, Smartquant will take longer to leanr, but it is ultimately much more powerful in my personal experience. I found the 1st month of building indicators,etc to be challenging as I was also learning how C# works. I can provide a couple words of advice ...
1) Get a book on C# and read it. This process a) helped me learn enough of C# to replicate what I did in NT and b) helped me learn other ways of approaching things that opened up new options.
2) Spend a bunch of time reading through the forum. There is a bunch of sample code scattered around that you can use as a guideline.
3) Learn to use Visual Studio to write your code and debug. All kinds of things got earier with that change.

So with that in mind, I'llpost again in a few minutes with some quick code answers to youposted questions.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 13, 2009 12:18 am 
Offline

Joined: Tue Jul 29, 2008 7:22 pm
Posts: 59
Location: Alberta, Canada
So a few comments first:
double Cmp = MOM1.Last + SMA1.Last;//this line compiles
(when you are creating the double "Cmp" you are creating a single number, not a series of numbers. As a result, when you later try to run this through an SMA, there is only 1 number, all the prvious values of Cmp are not remembered. In Ninjatrader, you would store all these previous values ina a DataSeries, but openQuant only provides BarSeries and TimesSeries in the API, not DataSeries ... So, the way to do it is to create a timeseries that stores "Cmp", then run the TimeSeries through SMA.


So Here is one way to do it ...

public class YourStrategyname: Strategy
{
[OptimizationParameter(160, 240, 20)]
[Parameter("SMALength")]
public int SMALength= 200;

TimeSeries CmpSeries;
SMA sma2;

public override void OnStrategyStart()
{
CmpSeries = new TimeSeries();
sma2 = new SMA(CmpSeries, SMALength);

sma2 .Color = Color.Blue;
sma2 .Width = 1;
Draw(sma2 , 0);

}
public override oid OnBar(Bar bar)
{
double Cmp = MOM1.Last + SMA1.Last
CmpSeries.Add(Bar.DateTime, Cmp);

// To reference prior Values of CmpSeries use CmpSeries.Ago(0) for
// most recent value, for prios one use CmpSeries.Ago(1) , etc.

}
}


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 13, 2009 1:30 am 
Offline

Joined: Wed Mar 11, 2009 9:54 pm
Posts: 63
Thank you Curios1!

This partually solved my problem

SMA1 = new SMA(TSeries, 10)*2;

It seems that it is impossible to use multiplication on TimeSeries?
Another puzle is visual studio 2008 does not recognize Sysem.Windows namespace?

Thank you again.

P.S I did read C# books and more, but I am a self made programmer without experience...

_________________
xtrender


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 13, 2009 1:50 am 
Offline

Joined: Wed Mar 11, 2009 9:54 pm
Posts: 63
I think I did something with the first question

Upper = SMA2.Last + SMA3.Last *2; //this compiles

But it seems like such a pain to end up with code broken into 10 lines of what originally was a very long but 1 line function! Same problem though was in NinjaTrader, there I just used a .Set() method.

Still can't add Drawing code in VS.

_________________
xtrender


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 19 posts ]  Go to page 1, 2  Next

All times are UTC + 3 hours


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group