/* This is -*- C -*- */ /* vim: set sw=2: */ /* * guppi-price-series-core-impl.c * * Copyright (C) 2000 EMC Capital Management, Inc. * Copyright (C) 2001 The Free Software Foundation * * Developed by Jon Trowbridge * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ #include #include "guppi-price-series-core.h" #include #include #include #include #include typedef struct _PriceDay PriceDay; struct _PriceDay { GDate dt; guint code; double op, hi, lo, cl, vo, oi; }; static GtkObjectClass *parent_class = NULL; static void guppi_price_series_core_finalize (GtkObject *obj) { GuppiPriceSeriesCore *core = GUPPI_PRICE_SERIES_CORE (obj); PriceDay **data; gint i; data = (PriceDay **)guppi_garray_data (core->garray); for (i=0; isize; ++i) { guppi_free (data[i]); data[i] = NULL; } guppi_unref0 (core->garray); if (parent_class->finalize) parent_class->finalize (obj); } /***************************************************************************/ static PriceDay* get_priceday (GuppiPriceSeriesCore *core, const GDate *date, gboolean create_if_missing) { gint i; PriceDay *pd; PriceDay **data; g_return_val_if_fail (core && GUPPI_IS_PRICE_SERIES_CORE (core), NULL); g_return_val_if_fail (date && g_date_valid ((GDate *) date), NULL); if (core->size == 0) { if (!create_if_missing) return NULL; pd = guppi_new0 (PriceDay, 1); pd->dt = *date; core->start_date = *date; core->end_date = *date; guppi_garray_set_size (core->garray, 186); core->size = 1; data = (PriceDay **)guppi_garray_data (core->garray); data[0] = pd; return pd; } i = (gint)g_date_julian ((GDate *) date) - (gint)g_date_julian (&core->start_date); if (0 <= i && i < core->size) { data = (PriceDay **) guppi_garray_data (core->garray); if (create_if_missing && data[i] == NULL) { pd = guppi_new0 (PriceDay, 1); pd->dt = *date; data[i] = pd; } /* Check that everything is still in sync. */ g_assert (data[i] == NULL || (g_date_compare (&(data[i]->dt), (GDate *) date) == 0)); return data[i]; } if (i < 0) { gint new_size, j; if (!create_if_missing) return NULL; new_size = core->size - i; if (guppi_garray_size (core->garray) < new_size) guppi_garray_set_size (core->garray, new_size); data = (PriceDay **) guppi_garray_data (core->garray); for (j = core->size-1; j >= 0; --j) data[j-i] = data[j]; for (j=1; j<-i; ++j) data[j] = NULL; pd = guppi_new0 (PriceDay, 1); pd->code = 0; pd->dt = *date; core->size = new_size; core->start_date = *date; data[0] = pd; return pd; } if (i >= core->size) { gint new_size, j; if (!create_if_missing) return NULL; new_size = i+1; if (guppi_garray_size (core->garray) < new_size) guppi_garray_set_size (core->garray, new_size); data = (PriceDay **) guppi_garray_data (core->garray); for (j = core->size; j < new_size-1; ++j) data[j] = NULL; pd = guppi_new0 (PriceDay, 1); pd->dt = *date; core->size = new_size; core->end_date = *date; data[i] = pd; return pd; } g_assert_not_reached (); return NULL; } static gint priceday_offset (guint code) { PriceDay pd; gpointer data; switch (code) { case PRICE_OPEN: data = &pd.op; break; case PRICE_HIGH: data = &pd.hi; break; case PRICE_LOW: data = &pd.lo; break; case PRICE_CLOSE: data = &pd.cl; break; case PRICE_VOLUME: data = &pd.vo; break; case PRICE_OPEN_INTEREST: data = &pd.oi; break; default: data = NULL; g_assert_not_reached (); } return (guchar *)data - (guchar *)&pd; } static GuppiData * v_data_copy (GuppiData *impl) { g_assert_not_reached (); return NULL; } static gint v_data_size_in_bytes (GuppiData *impl) { GuppiPriceSeriesCore *core = GUPPI_PRICE_SERIES_CORE (impl); gint x = 0; x += sizeof (GuppiPriceSeriesCore); x += core->size * sizeof (PriceDay); x += guppi_garray_size (core->garray) * sizeof (PriceDay *); return x; } static void v_dateind_bounds (GuppiDateIndexed *impl, GDate *start, GDate *end) { GuppiPriceSeriesCore *core = GUPPI_PRICE_SERIES_CORE (impl); if (start) *start = core->start_date; if (end) *end = core->end_date; } static gboolean v_dateind_valid (GuppiDateIndexed *impl, const GDate *date) { GuppiPriceSeriesCore *core = GUPPI_PRICE_SERIES_CORE (impl); PriceDay *pd; pd = get_priceday (core, date, FALSE); return pd && pd->code; } /* static gboolean v_dateind_step (GuppiDateIndexed *impl, const GDate *orig, gint delta, GDate *modified) { } */ static gint v_dateind_size (GuppiDateIndexed *impl) { GuppiPriceSeriesCore *core = GUPPI_PRICE_SERIES_CORE (impl); PriceDay **data; gint count = 0; gint i; data = (PriceDay **) guppi_garray_data (core->garray); for (i=0; i < core->size; ++i) if (data[i] != NULL && data[i]->code) ++count; return count; } static guint v_ps_valid (GuppiPriceSeries *impl, const GDate *date) { GuppiPriceSeriesCore *core = GUPPI_PRICE_SERIES_CORE (impl); PriceDay *pd; pd = get_priceday (core, date, FALSE); return pd ? pd->code : 0; } static double v_ps_get (GuppiPriceSeries *impl, guint code, const GDate *date) { GuppiPriceSeriesCore *core = GUPPI_PRICE_SERIES_CORE (impl); PriceDay *pd; pd = get_priceday (core, date, FALSE); if (pd == NULL || (pd->code & code) == 0) return 0; switch (code) { case PRICE_OPEN: return pd->op; case PRICE_HIGH: return pd->hi; case PRICE_LOW: return pd->lo; case PRICE_CLOSE: return pd->cl; case PRICE_VOLUME: return pd->vo; case PRICE_OPEN_INTEREST: return pd->oi; default: return 0; }; g_assert_not_reached(); return 0; } static void v_ps_set (GuppiPriceSeries *impl, guint code, const GDate *date, double x) { GuppiPriceSeriesCore *core = GUPPI_PRICE_SERIES_CORE (impl); PriceDay *pd; pd = get_priceday (core, date, TRUE); switch (code) { case PRICE_OPEN: pd->op = x; break; case PRICE_HIGH: pd->hi = x; break; case PRICE_LOW: pd->lo = x; break; case PRICE_CLOSE: pd->cl = x; break; case PRICE_VOLUME: pd->vo = x; break; case PRICE_OPEN_INTEREST: pd->oi = x; break; default: g_assert_not_reached(); } pd->code |= code; } static gint v_ps_get_many (GuppiPriceSeries *impl, const GDate *start_date, gint count, double *timestamp_buffer, double *open_buffer, double *high_buffer, double *low_buffer, double *close_buffer) { GuppiPriceSeriesCore *core = GUPPI_PRICE_SERIES_CORE (impl); PriceDay **data; PriceDay *day; gint sj, i, i1, j; sj = g_date_julian (&core->start_date); i = (gint)g_date_julian ((GDate *) start_date) - sj; i1 = (gint)g_date_julian (&core->end_date) - sj; data = (PriceDay **)guppi_garray_data (core->garray); j = 0; while (count && 0 <= i && i <= i1) { if ( (day = data[i]) ) { if (timestamp_buffer) timestamp_buffer[j] = sj + i; if (open_buffer) open_buffer[j] = day->op; if (high_buffer) high_buffer[j] = day->hi; if (low_buffer) low_buffer[j] = day->lo; if (close_buffer) close_buffer[j] = day->cl; ++j; if (count > 0) --count; else ++count; } if (count > 0) ++i; else --i; } return j; } static gint v_ps_get_range (GuppiPriceSeries *impl, const GDate *start_date, const GDate *end_date, double *timestamp_buffer, double *open_buffer, double *high_buffer, double *low_buffer, double *close_buffer) { GuppiPriceSeriesCore *core = GUPPI_PRICE_SERIES_CORE (impl); PriceDay **data; PriceDay *day; gint sj, i, j = 0, i0, i1; sj = g_date_julian (&core->start_date); i0 = (gint)g_date_julian ((GDate *) start_date) - sj; i1 = (gint)g_date_julian ((GDate *) end_date) - sj; data = (PriceDay **)guppi_garray_data (core->garray); for (i = i0; i <= i1; ++i) { if ( (day = data[i]) ) { if (timestamp_buffer) timestamp_buffer[j] = sj + i; if (open_buffer) open_buffer[j] = day->op; if (high_buffer) high_buffer[j] = day->hi; if (low_buffer) low_buffer[j] = day->lo; if (close_buffer) close_buffer[j] = day->cl; ++j; } } return j; } static gboolean v_ps_get_bounds (GuppiPriceSeries *impl, guint code, const GDate *start_date, const GDate *end_date, double *min, double *max) { GuppiPriceSeriesCore *core = GUPPI_PRICE_SERIES_CORE (impl); PriceDay **data; PriceDay *day; gint sj, i, i0, i1, offset; double x, m = 0, M = -1; gboolean first = TRUE; sj = g_date_julian (&core->start_date); i0 = (gint)g_date_julian ((GDate *) start_date) - sj; i1 = (gint)g_date_julian ((GDate *) end_date) - sj; data = (PriceDay **)guppi_garray_data (core->garray); offset = priceday_offset (code); for (i = i0; i <= i1; ++i) { if ( (day = data[i]) ) { x = *(double *)(((guchar *)day) + offset); if (first) { m = M = x; first = FALSE; } else { if (x < m) m = x; if (x > M) M = x; } } } if (!first) { if (min) *min = m; if (max) *max = M; } return !first; } /***************************************************************************/ static void guppi_price_series_core_class_init (GuppiPriceSeriesCoreClass *klass) { GtkObjectClass* object_class = (GtkObjectClass *)klass; GuppiDataClass *data_class = GUPPI_DATA_CLASS (klass); GuppiDateIndexedClass *dind_class = GUPPI_DATE_INDEXED_CLASS (klass); GuppiPriceSeriesClass *ps_class = GUPPI_PRICE_SERIES_CLASS (klass); parent_class = gtk_type_class(GUPPI_TYPE_PRICE_SERIES); object_class->finalize = guppi_price_series_core_finalize; data_class->is_leaf_type = TRUE; data_class->copy = v_data_copy; data_class->get_size_in_bytes = v_data_size_in_bytes; dind_class->bounds = v_dateind_bounds; dind_class->valid = v_dateind_valid; /* dind_class->step = v_dateind_step; */ dind_class->size = v_dateind_size; ps_class->valid = v_ps_valid; ps_class->get = v_ps_get; ps_class->set = v_ps_set; ps_class->get_many = v_ps_get_many; ps_class->get_range = v_ps_get_range; ps_class->get_bounds = v_ps_get_bounds; } static void guppi_price_series_core_init (GuppiPriceSeriesCore *obj) { g_date_clear (&obj->start_date, 1); g_date_clear (&obj->end_date, 1); obj->size = 0; obj->garray = guppi_garray_new (sizeof (PriceDay *)); } GtkType guppi_price_series_core_get_type (void) { static GtkType guppi_price_series_core_type = 0; if (!guppi_price_series_core_type) { static const GtkTypeInfo guppi_price_series_core_info = { "GuppiPriceSeriesCore", sizeof(GuppiPriceSeriesCore), sizeof(GuppiPriceSeriesCoreClass), (GtkClassInitFunc)guppi_price_series_core_class_init, (GtkObjectInitFunc)guppi_price_series_core_init, NULL, NULL, (GtkClassInitFunc)NULL }; guppi_price_series_core_type = gtk_type_unique (GUPPI_TYPE_PRICE_SERIES, &guppi_price_series_core_info); } return guppi_price_series_core_type; } GuppiPriceSeries * guppi_price_series_core_new (void) { return GUPPI_PRICE_SERIES (guppi_type_new (guppi_price_series_core_get_type ())); }