#include <iostream>
#include <string>
#include <vector>
#include <unordered_set>
#include <map>
#include <set>
#include <algorithm>
#include <cstdint>
#include <cmath>
#include <sstream>
#include <iomanip>
#include <cstring>

using namespace std;

struct Trade {
    uint64_t timestamp_ns;
    string symbol;
    double price;
    uint64_t qty;

    bool operator==(const Trade& other) const {
        return timestamp_ns == other.timestamp_ns &&
               symbol == other.symbol &&
               price == other.price &&
               qty == other.qty;
    }
};

struct TradeHash {
    size_t operator()(const Trade& t) const {
        size_t h1 = hash<uint64_t>()(t.timestamp_ns);
        size_t h2 = hash<string>()(t.symbol);
        uint64_t price_bits;
        memcpy(&price_bits, &t.price, sizeof(price_bits));
        size_t h3 = hash<uint64_t>()(price_bits);
        size_t h4 = hash<uint64_t>()(t.qty);
        return h1 ^ (h2 << 1) ^ (h3 << 2) ^ (h4 << 3);
    }
};

struct Bar {
    vector<double> prices;
    vector<uint64_t> quantities;
    uint64_t count;
};

struct BarOutput {
    uint64_t timestamp_second;
    string symbol;
    double open_price;
    double high;
    double low;
    double close;
    uint64_t volume;
    double vwap;
    uint64_t count;

    bool operator<(const BarOutput& other) const {
        if (timestamp_second != other.timestamp_second) {
            return timestamp_second < other.timestamp_second;
        }
        return symbol < other.symbol;
    }
};

bool parse_message(const string& line, Trade& trade) {
    size_t pos = 0;
    size_t next_pos = line.find('|');
    if (next_pos == string::npos) return false;

    string exchange = line.substr(pos, next_pos - pos);
    pos = next_pos + 1;

    try {
        if (exchange == "NYSE") {
            // NYSE|timestamp_ns|symbol|price|qty|side
            next_pos = line.find('|', pos);
            if (next_pos == string::npos) return false;
            trade.timestamp_ns = stoull(line.substr(pos, next_pos - pos));
            pos = next_pos + 1;

            next_pos = line.find('|', pos);
            if (next_pos == string::npos) return false;
            trade.symbol = line.substr(pos, next_pos - pos);
            pos = next_pos + 1;

            next_pos = line.find('|', pos);
            if (next_pos == string::npos) return false;
            trade.price = stod(line.substr(pos, next_pos - pos));
            pos = next_pos + 1;

            next_pos = line.find('|', pos);
            if (next_pos == string::npos) return false;
            trade.qty = stoull(line.substr(pos, next_pos - pos));

        } else if (exchange == "NASDAQ") {
            // NASDAQ|timestamp_us|symbol|side|qty|price
            next_pos = line.find('|', pos);
            if (next_pos == string::npos) return false;
            uint64_t timestamp_us = stoull(line.substr(pos, next_pos - pos));
            trade.timestamp_ns = timestamp_us * 1000;
            pos = next_pos + 1;

            next_pos = line.find('|', pos);
            if (next_pos == string::npos) return false;
            trade.symbol = line.substr(pos, next_pos - pos);
            pos = next_pos + 1;

            next_pos = line.find('|', pos);
            if (next_pos == string::npos) return false;
            // side = line.substr(pos, next_pos - pos);
            pos = next_pos + 1;

            next_pos = line.find('|', pos);
            if (next_pos == string::npos) return false;
            trade.qty = stoull(line.substr(pos, next_pos - pos));
            pos = next_pos + 1;

            trade.price = stod(line.substr(pos));

        } else if (exchange == "BATS") {
            // BATS|timestamp_ms|symbol|price|qty|side|trade_id
            next_pos = line.find('|', pos);
            if (next_pos == string::npos) return false;
            uint64_t timestamp_ms = stoull(line.substr(pos, next_pos - pos));
            trade.timestamp_ns = timestamp_ms * 1000000;
            pos = next_pos + 1;

            next_pos = line.find('|', pos);
            if (next_pos == string::npos) return false;
            trade.symbol = line.substr(pos, next_pos - pos);
            pos = next_pos + 1;

            next_pos = line.find('|', pos);
            if (next_pos == string::npos) return false;
            trade.price = stod(line.substr(pos, next_pos - pos));
            pos = next_pos + 1;

            next_pos = line.find('|', pos);
            if (next_pos == string::npos) return false;
            trade.qty = stoull(line.substr(pos, next_pos - pos));

        } else if (exchange == "IEX") {
            // IEX|timestamp_s.us|symbol|price|qty|side
            next_pos = line.find('|', pos);
            if (next_pos == string::npos) return false;
            string timestamp_str = line.substr(pos, next_pos - pos);
            pos = next_pos + 1;

            size_t dot_pos = timestamp_str.find('.');
            if (dot_pos == string::npos) return false;
            uint64_t seconds = stoull(timestamp_str.substr(0, dot_pos));
            uint64_t microseconds = stoull(timestamp_str.substr(dot_pos + 1));
            trade.timestamp_ns = seconds * 1000000000ULL + microseconds * 1000;

            next_pos = line.find('|', pos);
            if (next_pos == string::npos) return false;
            trade.symbol = line.substr(pos, next_pos - pos);
            pos = next_pos + 1;

            next_pos = line.find('|', pos);
            if (next_pos == string::npos) return false;
            trade.price = stod(line.substr(pos, next_pos - pos));
            pos = next_pos + 1;

            next_pos = line.find('|', pos);
            if (next_pos == string::npos) return false;
            trade.qty = stoull(line.substr(pos, next_pos - pos));

        } else {
            return false;
        }

        return true;
    } catch (...) {
        return false;
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    cin >> n;
    cin.ignore();

    unordered_set<Trade, TradeHash> seen_trades;
    map<pair<string, uint64_t>, Bar> bars;

    for (int i = 0; i < n; i++) {
        string line;
        getline(cin, line);

        Trade trade;
        if (!parse_message(line, trade)) {
            continue;
        }

        // Deduplication
        if (seen_trades.count(trade)) {
            continue;
        }
        seen_trades.insert(trade);

        // Group into 1-second bars
        uint64_t timestamp_second = trade.timestamp_ns / 1000000000ULL;
        auto bar_key = make_pair(trade.symbol, timestamp_second);

        bars[bar_key].prices.push_back(trade.price);
        bars[bar_key].quantities.push_back(trade.qty);
        bars[bar_key].count++;
    }

    // Compute OHLCV for each bar
    vector<BarOutput> results;
    for (auto& [bar_key, bar_data] : bars) {
        const string& symbol = bar_key.first;
        uint64_t timestamp_second = bar_key.second;
        const auto& prices = bar_data.prices;
        const auto& quantities = bar_data.quantities;
        uint64_t trade_count = bar_data.count;

        double open_price = prices[0];
        double high = *max_element(prices.begin(), prices.end());
        double low = *min_element(prices.begin(), prices.end());
        double close = prices[prices.size() - 1];

        uint64_t volume = 0;
        for (uint64_t q : quantities) {
            volume += q;
        }

        double vwap = 0.0;
        if (volume > 0) {
            double numerator = 0.0;
            for (size_t i = 0; i < prices.size(); i++) {
                numerator += prices[i] * quantities[i];
            }
            vwap = numerator / volume;
        }

        results.push_back({
            timestamp_second,
            symbol,
            open_price,
            high,
            low,
            close,
            volume,
            vwap,
            trade_count
        });
    }

    // Sort by (timestamp_second, symbol)
    sort(results.begin(), results.end());

    // Output
    set<string> unique_symbols;
    for (const auto& r : results) {
        unique_symbols.insert(r.symbol);
    }

    cout << unique_symbols.size() << " " << results.size() << "\n";
    cout << fixed << setprecision(6);
    for (const auto& r : results) {
        cout << r.timestamp_second << " " << r.symbol << " "
             << r.open_price << " " << r.high << " " << r.low << " " << r.close << " "
             << r.volume << " " << r.vwap << " " << r.count << "\n";
    }

    return 0;
}
