简体   繁体   中英

How to organize the structure of classes?

I am programming an advisor for trading in the foreign exchange market (binary options). Using FXCM API. For those who interesting. And I have a 5 currency pairs. Each of which contains the history of quotes in five different time frames. For example, let's say from one minute to five minutes. Each history must have three variables. (largest, smallest, last) The history of quotes is loaded from FXCM once in a time frame equal to one minute and then calculated for all other time frames. Also I have a methods (or maybe I can combine them into one method) for actual data which are executed once a minute, every two minutes, and so on, respectively, to record a newly formed candle in the corresponding history. I will attach a class structure that I see, but which I do not like.

class Pair:    
    def __init__(self, name):
        self.name = name

class Periods:     
    def __init__(self, name):
        self.name  = name
        self.one   = pd.DataFrame()
        self.two   = pd.DataFrame()
        self.three = pd.DataFrame()
        self.four  = pd.DataFrame()
        self.five  = pd.DataFrame()

    def get_historical_data(self): # Executed once
        self.one   = historical_data_one_minute
        self.two   = historical_data_two_minute
        self.three = historical_data_three_minute
        self.four  = historical_data_four_minute
        self.five  = historical_data_five_minute

    def set_actual_data(self, period): #Executed ones per minute
        if period == '1min':
            one_minute_candle = calculated_one_minute_candle
            self.one   = self.one.append(one_minute_candle)
        if period == '2min':
            two_minute_candle = calculated_two_minute_candle
            self.two   = self.two.append(two_minute_candle)
        ...

        if period == '5min':
            five_minute_candle = calculated_five_minute_candle
            self.five   = self.five.append(five_minute_candle)

As you noticed there is no largest, smallest and last variables. It's because I don't know how to tie them up. Should I to break 'Periods' into classes like One_minute, Two_minute and so on to add variables or there is another way? Will there be too many classes for this?

class One_minute:
    def __init__(self):
        self.largest = 0
        self.smallest = 0
        self.last = 0

    def get_historical_data(self):
        self.history = historical_data_one_minute
        self.largest = calculated_largest_from_historical_data_one_minute
        self.smallest = calculated_smallest_from_historical_data_one_minute
        self.last = calculated_last_from_historical_data_one_minute

In general, the structure is as follows

(currency pair) - one_minute_history ---- largest
                |                    |___ smallest
                |                    |___ last
                |_two_minute_history ---- largest
                |                    |___ smallest
                |                    |___ last
                |_and so on

Or

(currency pair) ------ one_minute_history
                 |  |_ largest
                 |  |_ smallest
                 |  |_ last
                 |____ two_minute_history
                 |  |_ largest
                 |  |_ smallest
                 |  |_ last
                 |____ three_minute_history
                  ...

It would be convenient if access was carried out like this

eurusd.history[1] #gets one minute history
eurusd.history[1].largest or eurusd.largest.history[1]  #gets largest price of one minute history

Or it could be something better.

In total, it turns out that I will have 25 different history data frames, 5 for each currency pair. And also for each history data frame, I will have three variables

I hope I could explain what I need to get. Thank you in advance!

Edit: I think it's no matter how historical data calculated but responding on your question - here is this method

    def get_historical_data(self, con): # Once
        dtn     = datetime.now()  
        hours   = dtn.hour + 3
        minutes = dtn.minute
    
        data = con.get_candles(instrument, period = 'm1', start=dtn - timedelta(hours=hours, minutes=minutes), end=dtn)        
        self.one['open']      = (data['bidopen']  + data['askopen'])  / 2
        self.one['high']      = (data['bidhigh']  + data['askhigh'])  / 2
        self.one['low']       = (data['bidlow']   + data['asklow'])   / 2
        self.one['close']     = (data['bidclose'] + data['askclose']) / 2
        self.one['direction'] = 'flat'
        self.one.loc[self.one['close'] - self.one['open'] >=  0.00002, "direction"] = "up"
        self.one.loc[self.one['close'] - self.one['open'] <= -0.00002, "direction"] = "down"
    
        s = (self.one['direction'] != self.one['direction'].shift()).cumsum()
        
        self.one['series'] = self.one.groupby(s).cumcount() + 1
        self.one.loc[self.one['direction'] == 'flat', 'series'] = self.one['series'].subtract(1)
        self.one = self.one.tz_localize(pytz.timezone('UTC'))
        self.one = self.one.tz_convert(pytz.timezone('Europe/Moscow'))    
        self.one.to_csv('history.csv', index=True)          
    
        dct = {'date': 'first', 'open': 'first', 'high': 'max', 'low': 'min', 'close': 'last'}
        
        self.two   = self.one.reset_index().groupby(np.arange(len(self.one)) // 2).agg(dct).set_index('date')
        self.three = self.one.reset_index().groupby(np.arange(len(self.one)) // 3).agg(dct).set_index('date')
        self.four  = self.one.reset_index().groupby(np.arange(len(self.one)) // 4).agg(dct).set_index('date')
        self.five  = self.one.reset_index().groupby(np.arange(len(self.one)) // 5).agg(dct).set_index('date')

The function is called in a loop.

con = fxcmpy.fxcmpy(config_file = 'fxcm.cfg') # Connection
periods = Periods("EUR/USD")
cycle_just_launched = True
while True:
    time.sleep(60)
    if cycle_just_launched:
        periods.get_historical_data(con)
    else:
        periods.set_actual_data(con, "1min")
    cycle_just_launched = False

Seems like you need to encapsulate the concept of a "single-period history" and then you can build the rest on top of that. Something like:

class PeriodHistory:
    def __init__(self, name, period):
        self.name = name
        self.period = period # e.g. 1min, 2min, etc.
        self.data = pd.DataFrame()
        self.largest = 0
        self.smallest = 0
        self.latest = 0

    def load(self, historic_data):
        # initialize data, largest, smallest, latest from historical

    def update(self, new_data):
        # update variables based on new data and self.period

Then a class to combine multi-period histories into one:

class MultiPeriodHistory:
    def __init__(self, name):
        self.name = name
        self.period = {}
        for i in range(1, 6):
            self.period[i] = PeriodHistory(self.name, i)
            self.period[i].load(history_data_for_period[i])

    def update(self):
        new_data = get_data_from_api(self.name)
        for i in range(1, 6):
            self.period[i].update(new_data)

And then you can use a dict to store multi-history for each currency pair:

currencies = ('eur', 'usd', 'jpy', 'gbp', 'chf')
history = {}
for c1 in currencies:
    for c2 in currencies:
        if c1 != c2:
            history[c1 + c2] = MultiPeriodHistory(c1 + c2)

Now eg history['eurgbp'].period[3].smallest will give you what you want.

You may need to modify your data fetch and update a bit to fit this pattern, I hand-waved a lot since I don't have the full picture.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM