import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

# [(Snapshot_Time, [(buy_price1, amount1), ...] , [(sell_price1, amount1), ...]), ...]
# [(1620457034392, [(56000, 0.01), (55900, 1), (55700, 30), ...] , [(57000, 0.01), (57100, 1), ...] ), (1620457034394, [...]), ...]
# The snapshots should has almost identical time-interval. Good for LSTM. 
# Time axis: [history, older, newer, ..., latest]
realtime_shortterm_dataset_aggtrade = []
realtime_shortterm_dataset_aggtrade_size = 1024

# [(Trade_Time, PRICE, AMOUNT), ...]
# [(1620457034392, 56000, 0.5), (1620457034394, 56001, 0.05), ...]
# The trades usually have various time-interval. TODO: transform it to [(WeightedAvgPrice, Volume), ...] for every 1 minutes? 
# Time axis: [history, older, newer, ..., latest]
realtime_shortterm_dataset_depth = []
realtime_shortterm_dataset_depth_size = 1024*1024

# The trading thread would not start working, before finish analysing longterm dataset. 
# Time-interval for longterm dataset is 1 minute.
longterm_dataset = []


class LSTM_Shortterm_Predictor(nn.Module):
    def __init__(self, input_dim, hidden_dim):
        super(LSTMTagger, self).__init__()
        self.hidden_dim = hidden_dim

        # The input would be a tuple containing complex information. 
        # Firstly, serialize these information into a tuple. 
        self.serializer = nn.Linear(input_dim, lstm_idim)

        # The LSTM hidden states
        # with dimensionality hidden_dim.
        self.lstm = nn.LSTM(lstm_idim, lstm_odim)

        # The linear layer that maps from hidden state space to tag space
        self.out = nn.Linear(hidden_odim, 1)

    def forward(self, sample_seq):
        input_seq = sample_seq.view(len(sample_seq), 1, 1)
        lstm_in = self.serializer(input_seq)
        lstm_out, _ = self.lstm(lstm_in)
        predict_shortterm_trend = self.out(torch.tanh(lstm_out[-1:]))
        return predict_shortterm_trend

def aggtrade_to_impulsive_score_vector(aggtrade):
    _, buys, sells = aggtrade
    def get_factors(array_of_pairs):
        values = [pair[0] for pair in array_of_pairs]
        weights = [pair[1] for pair in array_of_pairs]
        average = numpy.average(values, weights=weights)
        variance = numpy.average((values-average)**2, weights=weights)
        leader_price, leader_weight = array_of_pairs[0]
        return (average, math.sqrt(variance), leader_price, leader_weight)

    return get_factors(buys) + get_factors(sells)
    


