# Authors: Lars Buitinck <L.J.Buitinck@uva.nl>
#          Dan Blanchard <dblanchard@ets.org>
# License: BSD 3 clause

from random import Random
import numpy as np
import scipy.sparse as sp

from numpy.testing import assert_array_equal
from sklearn.utils.testing import (assert_equal, assert_in,
                                   assert_false, assert_true)

from sklearn.feature_extraction import DictVectorizer
from sklearn.feature_selection import SelectKBest, chi2

def test_dictvectorizer():
    D = [{"foo": 1, "bar": 3},
         {"bar": 4, "baz": 2},
         {"bar": 1, "quux": 1, "quuux": 2}]

    for sparse in (True, False):
        for dtype in (int, np.float32, np.int16):
            for sort in (True, False):
                for iterable in (True, False):
                    v = DictVectorizer(sparse=sparse, dtype=dtype, sort=sort)
                    X = v.fit_transform(iter(D) if iterable else D)

                    assert_equal(sp.issparse(X), sparse)
                    assert_equal(X.shape, (3, 5))
                    assert_equal(X.sum(), 14)
                    assert_equal(v.inverse_transform(X), D)

                    if sparse:
                        # CSR matrices can't be compared for equality
                        assert_array_equal(X.A, v.transform(iter(D) if iterable
                                                            else D).A)
                    else:
                        assert_array_equal(X, v.transform(iter(D) if iterable
                                                          else D))

                    if sort:
                        assert_equal(v.feature_names_,
                                     sorted(v.feature_names_))

def test_feature_selection():
    # make two feature dicts with two useful features and a bunch of useless
    # ones, in terms of chi2
    d1 = dict([("useless%d" % i, 10) for i in range(20)],
              useful1=1, useful2=20)
    d2 = dict([("useless%d" % i, 10) for i in range(20)],
              useful1=20, useful2=1)

    for indices in (True, False):
        v = DictVectorizer().fit([d1, d2])
        X = v.transform([d1, d2])
        sel = SelectKBest(chi2, k=2).fit(X, [0, 1])

        v.restrict(sel.get_support(indices=indices), indices=indices)
        assert_equal(v.get_feature_names(), ["useful1", "useful2"])

def test_one_of_k():
    D_in = [{"version": "1", "ham": 2},
            {"version": "2", "spam": .3},
            {"version=3": True, "spam": -1}]
    v = DictVectorizer()
    X = v.fit_transform(D_in)
    assert_equal(X.shape, (3, 5))

    D_out = v.inverse_transform(X)
    assert_equal(D_out[0], {"version=1": 1, "ham": 2})

    names = v.get_feature_names()
    assert_true("version=2" in names)
    assert_false("version" in names)

def test_unseen_or_no_features():
    D = [{"camelot": 0, "spamalot": 1}]
    for sparse in [True, False]:
        v = DictVectorizer(sparse=sparse).fit(D)

        X = v.transform({"push the pram a lot": 2})
        if sparse:
            X = X.toarray()
        assert_array_equal(X, np.zeros((1, 2)))

        X = v.transform({})
        if sparse:
            X = X.toarray()
        assert_array_equal(X, np.zeros((1, 2)))

        try:
            v.transform([])
        except ValueError as e:
            assert_in("empty", str(e))

def test_deterministic_vocabulary():
    # Generate equal dictionaries with different memory layouts
    items = [("%03d" % i, i) for i in range(1000)]
    rng = Random(42)
    d_sorted = dict(items)
    rng.shuffle(items)
    d_shuffled = dict(items)

    # check that the memory layout does not impact the resulting vocabulary
    v_1 = DictVectorizer().fit([d_sorted])
    v_2 = DictVectorizer().fit([d_shuffled])

    assert_equal(v_1.vocabulary_, v_2.vocabulary_)


# coding: utf-8

# Author: Johannes Schönberger
#
# License: BSD 3 clause

import numpy as np

from ..base import BaseEstimator, MetaEstimatorMixin, RegressorMixin, clone
from ..utils import check_random_state, check_array, check_consistent_length
from ..utils.random import sample_without_replacement
from ..utils.validation import check_is_fitted
from .base import LinearRegression

_EPSILON = np.spacing(1)

def _dynamic_max_trials(n_inliers, n_samples, min_samples, probability):
    """Determine number trials such that at least one outlier-free subset is
    sampled for the given inlier/outlier ratio.

    Parameters
    ----------
    n_inliers : int
        Number of inliers in the data.

    n_samples : int
        Total number of samples in the data.

    min_samples : int
        Minimum number of samples chosen randomly from original data.

    probability : float
        Probability (confidence) that one outlier-free sample is generated.

    Returns
    -------
    trials : int
        Number of trials.

    """
    inlier_ratio = n_inliers / float(n_samples)
    nom = max(_EPSILON, 1 - probability)
    denom = max(_EPSILON, 1 - inlier_ratio ** min_samples)
    if nom == 1:
        return 0
    if denom == 1:
        return float('inf')
    return abs(float(np.ceil(np.log(nom) / np.log(denom))))

class RANSACRegressor(BaseEstimator, MetaEstimatorMixin, RegressorMixin):
    """RANSAC (RANdom SAmple Consensus) algorithm.

    RANSAC is an iterative algorithm for the robust estimation of parameters
    from a subset of inliers from the complete data set. More information can
    be found in the general documentation of linear models.

    A detailed description of the algorithm can be found in the documentation
    of the ``linear_model`` sub-package.

    Read more in the :ref:`User Guide <RansacRegression>`.

    Parameters
    ----------
    base_estimator : object, optional
        Base estimator object which implements the following methods:

         * `fit(X, y)`: Fit model to given training data and target values.
         * `score(X, y)`: Returns the mean accuracy on the given test data,
           which is used for the stop criterion defined by `stop_score`.
           Additionally, the score is used to decide which of two equally
           large consensus sets is chosen as the better one.

        If `base_estimator` is None, then
        ``base_estimator=sklearn.linear_model.LinearRegression()`` is used for
        target values of dtype float.

        Note that the current implementation only supports regression
        estimators.

    min_samples : int (>= 1) or float ([0, 1]), optional
        Minimum number of samples chosen randomly from original data. Treated
        as an absolute number of samples for `min_samples >= 1`, treated as a
        relative number `ceil(min_samples * X.shape[0]`) for
        `min_samples < 1`. This is typically chosen as the minimal number of
        samples necessary to estimate the given `base_estimator`. By default a
        ``sklearn.linear_model.LinearRegression()`` estimator is assumed and
        `min_samples` is chosen as ``X.shape[1] + 1``.

    residual_threshold : float, optional
        Maximum residual for a data sample to be classified as an inlier.
        By default the threshold is chosen as the MAD (median absolute
        deviation) of the target values `y`.

    is_data_valid : callable, optional
        This function is called with the randomly selected data before the
        model is fitted to it: `is_data_valid(X, y)`. If its return value is
        False the current randomly chosen sub-sample is skipped.

    is_model_valid : callable, optional
        This function is called with the estimated model and the randomly
        selected data: `is_model_valid(model, X, y)`. If its return value is
        False the current randomly chosen sub-sample is skipped.
        Rejecting samples with this function is computationally costlier than
        with `is_data_valid`. `is_model_valid` should therefore only be used if
        the estimated model is needed for making the rejection decision.

    max_trials : int, optional
        Maximum number of iterations for random sample selection.

    stop_n_inliers : int, optional
        Stop iteration if at least this number of inliers are found.

    stop_score : float, optional
        Stop iteration if score is greater equal than this threshold.

    stop_probability : float in range [0, 1], optional
        RANSAC iteration stops if at least one outlier-free set of the training
        data is sampled in RANSAC. This requires to generate at least N
        samples (iterations)::

            N >= log(1 - probability) / log(1 - e**m)

        where the probability (confidence) is typically set to high value such
        as 0.99 (the default) and e is the current fraction of inliers w.r.t.
        the total number of samples.

    residual_metric : callable, optional
        Metric to reduce the dimensionality of the residuals to 1 for
        multi-dimensional target values ``y.shape[1] > 1``. By default the sum
        of absolute differences is used::

            lambda dy: np.sum(np.abs(dy), axis=1)

    random_state : integer or numpy.RandomState, optional
        The generator used to initialize the centers. If an integer is
        given, it fixes the seed. Defaults to the global numpy random
        number generator.

    Attributes
    ----------
    estimator_ : object
        Best fitted model (copy of the `base_estimator` object).

    n_trials_ : int
        Number of random selection trials until one of the stop criteria is
        met. It is always ``<= max_trials``.

    inlier_mask_ : bool array of shape [n_samples]
        Boolean mask of inliers classified as ``True``.

    References
    ----------
    .. [1] http://en.wikipedia.org/wiki/RANSAC
    .. [2] http://www.cs.columbia.edu/~belhumeur/courses/compPhoto/ransac.pdf
    .. [3] http://www.bmva.org/bmvc/2009/Papers/Paper355/Paper355.pdf
    """

    def __init__(self, base_estimator=None, min_samples=None,
                 residual_threshold=None, is_data_valid=None,
                 is_model_valid=None, max_trials=100,
                 stop_n_inliers=np.inf, stop_score=np.inf,
                 stop_probability=0.99, residual_metric=None,
                 random_state=None):

        self.base_estimator = base_estimator
        self.min_samples = min_samples
        self.residual_threshold = residual_threshold
        self.is_data_valid = is_data_valid
        self.is_model_valid = is_model_valid
        self.max_trials = max_trials
        self.stop_n_inliers = stop_n_inliers
        self.stop_score = stop_score
        self.stop_probability = stop_probability
        self.residual_metric = residual_metric
        self.random_state = random_state

    def fit(self, X, y):
        """Fit estimator using RANSAC algorithm.

        Parameters
        ----------
        X : array-like or sparse matrix, shape [n_samples, n_features]
            Training data.

        y : array-like, shape = [n_samples] or [n_samples, n_targets]
            Target values.

        Raises
        ------
        ValueError
            If no valid consensus set could be found. This occurs if
            `is_data_valid` and `is_model_valid` return False for all
            `max_trials` randomly chosen sub-samples.

        """
        X = check_array(X, accept_sparse='csr')
        y = check_array(y, ensure_2d=False)
        check_consistent_length(X, y)

        if self.base_estimator is not None:
            base_estimator = clone(self.base_estimator)
        else:
            base_estimator = LinearRegression()

        if self.min_samples is None:
            # assume linear model by default
            min_samples = X.shape[1] + 1
        elif 0 < self.min_samples < 1:
            min_samples = np.ceil(self.min_samples * X.shape[0])
        elif self.min_samples >= 1:
            if self.min_samples % 1 != 0:
                raise ValueError("Absolute number of samples must be an "
                                 "integer value.")
            min_samples = self.min_samples
        else:
            raise ValueError("Value for `min_samples` must be scalar and "
                             "positive.")
        if min_samples > X.shape[0]:
            raise ValueError("`min_samples` may not be larger than number "
                             "of samples ``X.shape[0]``.")

        if self.stop_probability < 0 or self.stop_probability > 1:
            raise ValueError("`stop_probability` must be in range [0, 1].")

        if self.residual_threshold is None:
            # MAD (median absolute deviation)
            residual_threshold = np.median(np.abs(y - np.median(y)))
        else:
            residual_threshold = self.residual_threshold

        if self.residual_metric is None:
            residual_metric = lambda dy: np.sum(np.abs(dy), axis=1)
        else:
            residual_metric = self.residual_metric

        random_state = check_random_state(self.random_state)

        try:  # Not all estimator accept a random_state
            base_estimator.set_params(random_state=random_state)
        except ValueError:
            pass

        n_inliers_best = 0
        score_best = np.inf
        inlier_mask_best = None
        X_inlier_best = None
        y_inlier_best = None

        # number of data samples
        n_samples = X.shape[0]
        sample_idxs = np.arange(n_samples)

        n_samples, _ = X.shape

        for self.n_trials_ in range(1, self.max_trials + 1):

            # choose random sample set
            subset_idxs = sample_without_replacement(n_samples, min_samples,
                                                     random_state=random_state)
            X_subset = X[subset_idxs]
            y_subset = y[subset_idxs]

            # check if random sample set is valid
            if (self.is_data_valid is not None
                    and not self.is_data_valid(X_subset, y_subset)):
                continue

            # fit model for current random sample set
            base_estimator.fit(X_subset, y_subset)

            # check if estimated model is valid
            if (self.is_model_valid is not None and not
                    self.is_model_valid(base_estimator, X_subset, y_subset)):
                continue

            # residuals of all data for current random sample model
            y_pred = base_estimator.predict(X)
            diff = y_pred - y
            if diff.ndim == 1:
                diff = diff.reshape(-1, 1)
            residuals_subset = residual_metric(diff)

            # classify data into inliers and outliers
            inlier_mask_subset = residuals_subset < residual_threshold
            n_inliers_subset = np.sum(inlier_mask_subset)

            # less inliers -> skip current random sample
            if n_inliers_subset < n_inliers_best:
                continue
            if n_inliers_subset == 0:
                raise ValueError("No inliers found, possible cause is "
                    "setting residual_threshold ({0}) too low.".format(
                    self.residual_threshold))

            # extract inlier data set
            inlier_idxs_subset = sample_idxs[inlier_mask_subset]
            X_inlier_subset = X[inlier_idxs_subset]
            y_inlier_subset = y[inlier_idxs_subset]

            # score of inlier data set
            score_subset = base_estimator.score(X_inlier_subset,
                                                y_inlier_subset)

            # same number of inliers but worse score -> skip current random
            # sample
            if (n_inliers_subset == n_inliers_best
                    and score_subset < score_best):
                continue

            # save current random sample as best sample
            n_inliers_best = n_inliers_subset
            score_best = score_subset
            inlier_mask_best = inlier_mask_subset
            X_inlier_best = X_inlier_subset
            y_inlier_best = y_inlier_subset

            # break if sufficient number of inliers or score is reached
            if (n_inliers_best >= self.stop_n_inliers
                    or score_best >= self.stop_score
                    or self.n_trials_
                       >= _dynamic_max_trials(n_inliers_best, n_samples,
                                              min_samples,
                                              self.stop_probability)):
                break

        # if none of the iterations met the required criteria
        if inlier_mask_best is None:
            raise ValueError(
                "RANSAC could not find valid consensus set, because"
                " either the `residual_threshold` rejected all the samples or"
                " `is_data_valid` and `is_model_valid` returned False for all"
                " `max_trials` randomly ""chosen sub-samples. Consider "
                "relaxing the ""constraints.")

        # estimate final model using all inliers
        base_estimator.fit(X_inlier_best, y_inlier_best)

        self.estimator_ = base_estimator
        self.inlier_mask_ = inlier_mask_best
        return self

    def predict(self, X):
        """Predict using the estimated model.

        This is a wrapper for `estimator_.predict(X)`.

        Parameters
        ----------
        X : numpy array of shape [n_samples, n_features]

        Returns
        -------
        y : array, shape = [n_samples] or [n_samples, n_targets]
            Returns predicted values.
        """
        check_is_fitted(self, 'estimator_')

        return self.estimator_.predict(X)

    def score(self, X, y):
        """Returns the score of the prediction.

        This is a wrapper for `estimator_.score(X, y)`.

        Parameters
        ----------
        X : numpy array or sparse matrix of shape [n_samples, n_features]
            Training data.

        y : array, shape = [n_samples] or [n_samples, n_targets]
            Target values.

        Returns
        -------
        z : float
            Score of the prediction.
        """
        check_is_fitted(self, 'estimator_')

        return self.estimator_.score(X, y)


# demo inspired by: http://matplotlib.org/examples/pylab_examples/contour_demo.html

from bokeh import mpl
from bokeh.plotting import output_file, show

import matplotlib
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
import numpy as np

matplotlib.rcParams['xtick.direction'] = 'out'
matplotlib.rcParams['ytick.direction'] = 'out'

delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
# difference of Gaussians
Z = 10.0 * (Z2 - Z1)

# Create a simple contour plot with labels using default colors.  The
# inline argument to clabel will control whether the labels are draw
# over the line segments of the contour, removing the lines beneath
# the label
plt.figure()
CS = plt.contour(X, Y, Z)
plt.clabel(CS, inline=1, fontsize=10)
plt.title('Simplest default with labels')

output_file("mpl_contour.html", title="mpl_contour.py example")

show(mpl.to_bokeh())


import sys, pickle, copy
import numpy as np
import matplotlib.pyplot as pl

import astropy.io.fits as pyfits
import magellanic.regionsed as rsed
import magellanic.mcutils as utils
from magellanic.lfutils import *

try:
    import fsps
    from sedpy import observate
except ImportError:
    #you wont be able to predict the integrated spectrum or magnitudes
    # filterlist must be set to None in calls to total_cloud_data
    sps = None

wlengths = {'2': '{4.5\mu m}',
            '4': '{8\mu m}'}

dmod = {'smc':18.9,
        'lmc':18.5}

cloud_info = {}
cloud_info['smc'] = [utils.smc_regions(), 20, 23, [7, 13, 16], [3,5,6]]
cloud_info['lmc'] = [utils.lmc_regions(), 48, 38, [7, 11, 13, 16], [3,4,5,6]]

def total_cloud_data(cloud, filternames = None, basti=False,
                     lfstring=None, agb_dust=1.0,
                     one_metal=None):

    #########
    # SPS
    #########
    #
    if filternames is not None:
        sps = fsps.StellarPopulation(add_agb_dust_model=True)
        sps.params['sfh'] = 0
        sps.params['agb_dust'] = agb_dust
        dust = ['nodust', 'agbdust']
        sps.params['imf_type'] = 0.0 #salpeter
        filterlist = observate.load_filters(filternames)
    else:
        filterlist = None
    ##########
    # SFHs
    ##########
    regions, nx, ny, zlist, zlist_basti = cloud_info[cloud.lower()]
    if basti:
            zlist = basti_zlist
    if 'header' in regions.keys():
        rheader = regions.pop('header') #dump the header info from the reg. dict
    total_sfhs = None
    for n, dat in regions.iteritems():
        total_sfhs = sum_sfhs(total_sfhs, dat['sfhs'])
        total_zmet = dat['zmet']
    #collapse SFHs to one metallicity
    if one_metal is not None:
        ts = None
        for sfh in total_sfhs:
            ts = sum_sfhs(ts, sfh)
        total_sfh = ts
        zlist = [zlist[one_metal]]
        total_zmet = [total_zmet[one_metal]]
    #############
    # LFs
    ############
    bins = rsed.lfbins
    if lfstring is not None:
        # these are stored as a list of different metallicities
        lffiles = [lfstring.format(z) for z in zlist]
        lf_base = [read_villaume_lfs(f) for f in lffiles]
        #get LFs broken out by age and metallicity as well as the total
        lfs_zt, lf, logages = rsed.one_region_lfs(copy.deepcopy(total_sfhs), lf_base)
    else:
        lfs_zt, lf, logages = None, None, None
    ###########
    # SED
    ############
    if filterlist is not None:
        spec, wave, mass = rsed.one_region_sed(copy.deepcopy(total_sfhs), total_zmet, sps)
        mags = observate.getSED(wave, spec*rsed.to_cgs, filterlist=filterlist)
        maggies = 10**(-0.4 * np.atleast_1d(mags))
    else:
        maggies, mass = None, None

    #############
    # Write output
    ############
    total_values = {}
    total_values['agb_clf'] = lf
    total_values['agb_clfs_zt'] = lfs_zt
    total_values['clf_mags'] = bins
    total_values['logages'] = logages
    total_values['sed_ab_maggies'] = maggies
    total_values['sed_filters'] = filternames
    total_values['lffile'] = lfstring
    total_values['mstar'] = mass
    total_values['zlist'] = zlist
    return total_values, total_sfhs

def sum_sfhs(sfhs1, sfhs2):
    """
    Accumulate individual sets of SFHs into a total set of SFHs.  This
    assumes that the individual SFH sets all have the same number and
    order of metallicities, and the same time binning.
    """
    if sfhs1 is None:
        return copy.deepcopy(sfhs2)
    elif sfhs2 is None:
        return copy.deepcopy(sfhs1)
    else:
        out = copy.deepcopy(sfhs1)
        for s1, s2 in zip(out, sfhs2):
            s1['sfr'] += s2['sfr']
        return out

if __name__ == '__main__':

    filters = ['galex_NUV', 'spitzer_irac_ch2',
               'spitzer_irac_ch4', 'spitzer_mips_24']
    #filters = None

    ldir, cdir = 'lf_data/', 'composite_lfs/'
    outst = '{0}_n2teffcut.p'
    # total_cloud_data will loop over the appropriate (for the
    # isochrone) metallicities for a given lfst filename template
    lfst = '{0}z{{0:02.0f}}_tau{1:2.1f}_vega_irac{2}_n2_teffcut_lf.txt'
    basti = False
    agb_dust=1.0
    agebins = np.arange(9)*0.3 + 7.4

    #loop over clouds (and bands and agb_dust) to produce clfs
    for cloud in ['smc']:
        rdir = '{0}cclf_{1}_'.format(cdir, cloud)
        for band in ['2','4']:
            lfstring = lfst.format(ldir, agb_dust, band)
            dat, sfhs = total_cloud_data(cloud, filternames=filters, agb_dust=agb_dust,
                                         lfstring=lfstring, basti=basti)
            agebins = sfhs[0]['t1'][3:-1]
            outfile = lfstring.replace(ldir, rdir).replace('z{0:02.0f}_','').replace('.txt','.dat')
            write_clf_many([dat['clf_mags'], dat['agb_clf']], outfile, lfstring)

            #fig, ax = plot_weighted_lfs(dat, agebins = agebins, dm=dmod[cloud])
            #fig.suptitle('{0} @ IRAC{1}'.format(cloud.upper(), band))
            #fig.savefig('byage_clfs/{0}_clfs_by_age_and_Z_irac{1}'.format(cloud, band))
            #pl.close(fig)

            colheads = (len(agebins)-1) * ' N<m(t={})'
            colheads = colheads.format(*(agebins[:-1]+agebins[1:])/2.)
            tbin_lfs = np.array([rebin_lfs(lf, ages, agebins) for lf, ages
                                 in zip(dat['agb_clfs_zt'], dat['logages'])])
            write_clf_many([dat['clf_mags'], tbin_lfs.sum(axis=0)],
                           outfile.replace(cdir,'byage_clfs/'), lfstring,
                           colheads=colheads)

        pl.figure()
        for s, z in zip(sfhs, dat['zlist']):
            pl.step(s['t1'], s['sfr'], where='post', label='zind={0}'.format(z), linewidth=3)
        pl.legend(loc=0)
        pl.title(cloud.upper())

        print(cloud, dat['mstar'])


# encoding: UTF-8

"""
缠论模块相关的GUI控制组件
"""
from vtGateway import VtSubscribeReq
from uiBasicWidget import QtGui, QtCore, BasicCell,BasicMonitor,TradingWidget
from eventEngine import *
from ctaBase import *
import pyqtgraph as pg
import numpy as np
import pymongo
from pymongo.errors import *
from datetime import datetime, timedelta
from ctaHistoryData import HistoryDataEngine
import time
import types
import pandas as pd
########################################################################
class MyStringAxis(pg.AxisItem):
    def __init__(self, xdict, *args, **kwargs):
        pg.AxisItem.__init__(self, *args, **kwargs)
        self.x_values = np.asarray(xdict.keys())
        self.x_strings = xdict.values()

    def tickStrings(self, values, scale, spacing):
        strings = []
        for v in values:
            # vs is the original tick value
            vs = v * scale
            # if we have vs in our values, show the string
            # otherwise show nothing
            if vs in self.x_values:
                # Find the string with x_values closest to vs
                vstr = self.x_strings[np.abs(self.x_values - vs).argmin()]
            else:
                vstr = ""
            strings.append(vstr)
        return strings

########################################################################
class ChanlunEngineManager(QtGui.QWidget):
    """chanlun引擎管理组件"""
    signal = QtCore.pyqtSignal(type(Event()))

    # ----------------------------------------------------------------------
    def __init__(self, chanlunEngine, eventEngine, mainEngine, parent=None):
        """Constructor"""
        super(ChanlunEngineManager, self).__init__(parent)

        self.chanlunEngine = chanlunEngine
        self.eventEngine = eventEngine
        self.mainEngine = mainEngine

        self.penLoaded = False
        self.segmentLoaded = False
        self.tickLoaded = False
        self.zhongShuLoaded = False
        self.instrumentid = ''

        self.initUi()
        self.registerEvent()

        # 记录日志
        self.chanlunEngine.writeChanlunLog(u'缠论引擎启动成功')

        # ----------------------------------------------------------------------

    def initUi(self):
        """初始化界面"""
        self.setWindowTitle(u'缠论策略')

        # 期货代码输入框
        self.codeEdit = QtGui.QLineEdit()
        self.codeEdit.setPlaceholderText(u'在此输入期货代码')
        self.codeEdit.setMaximumWidth(200)
        self.data = pd.DataFrame() #画图所需数据, 重要
        self.fenX = [] #分笔分段所需X轴坐标
        self.fenY = [] #分笔分段所需Y轴坐标
        self.zhongshuPos = [] #中枢的位置
        self.zhongShuType = [] #中枢的方向
        # 金融图
        self.PriceW = PriceWidget(self.eventEngine, self.chanlunEngine, self.data)
        self.TickW = None

        # MongoDB数据库相关
        self.__mongoConnected = False
        self.__mongoConnection = None

        # 调用函数
        self.__connectMongo()

        # 按钮
        penButton = QtGui.QPushButton(u'分笔')
        segmentButton = QtGui.QPushButton(u'分段')
        zhongshuButton = QtGui.QPushButton(u'走势中枢')
        shopButton = QtGui.QPushButton(u'买卖点')
        restoreButton = QtGui.QPushButton(u'还原')

        penButton.clicked.connect(self.pen)
        segmentButton.clicked.connect(self.segment)
        zhongshuButton.clicked.connect(self.zhongShu)
        shopButton.clicked.connect(self.shop)
        restoreButton.clicked.connect(self.restore)

        # Chanlun组件的日志监控
        self.chanlunLogMonitor = QtGui.QTextEdit()
        self.chanlunLogMonitor.setReadOnly(True)
        self.chanlunLogMonitor.setMaximumHeight(180)

        # 设置布局
        self.hbox2 = QtGui.QHBoxLayout()
        self.hbox2.addWidget(self.codeEdit)
        self.hbox2.addWidget(penButton)
        self.hbox2.addWidget(segmentButton)
        self.hbox2.addWidget(zhongshuButton)
        self.hbox2.addWidget(shopButton)
        self.hbox2.addWidget(restoreButton)
        self.hbox2.addStretch()

        tickButton = QtGui.QPushButton(u'Tick')
        oneMButton = QtGui.QPushButton(u"1分")
        fiveMButton = QtGui.QPushButton(u'5分')
        fifteenMButton = QtGui.QPushButton(u'15分')
        thirtyMButton = QtGui.QPushButton(u'30分')
        sixtyMButton = QtGui.QPushButton(u'60分')
        dayButton = QtGui.QPushButton(u'日')
        weekButton = QtGui.QPushButton(u'周')
        monthButton = QtGui.QPushButton(u'月')

        oneMButton.checked = True

        self.vbox1 = QtGui.QVBoxLayout()

        tickButton.clicked.connect(self.openTick)
        oneMButton.clicked.connect(self.oneM)
        fiveMButton.clicked.connect(self.fiveM)
        fifteenMButton.clicked.connect(self.fifteenM)
        thirtyMButton.clicked.connect(self.thirtyM)
        sixtyMButton.clicked.connect(self.sixtyM)
        dayButton.clicked.connect(self.daily)
        weekButton.clicked.connect(self.weekly)
        monthButton.clicked.connect(self.monthly)

        self.vbox2 = QtGui.QVBoxLayout()
        self.vbox1.addWidget(self.PriceW)
        self.vbox2.addWidget(tickButton)
        self.vbox2.addWidget(oneMButton)
        self.vbox2.addWidget(fiveMButton)
        self.vbox2.addWidget(fifteenMButton)
        self.vbox2.addWidget(thirtyMButton)
        self.vbox2.addWidget(sixtyMButton)
        self.vbox2.addWidget(dayButton)
        self.vbox2.addWidget(weekButton)
        self.vbox2.addWidget(monthButton)
        self.vbox2.addStretch()

        self.hbox3 = QtGui.QHBoxLayout()
        self.hbox3.addStretch()
        self.hbox3.addLayout(self.vbox1)
        self.hbox3.addLayout(self.vbox2)

        self.vbox = QtGui.QVBoxLayout()
        self.vbox.addLayout(self.hbox2)
        self.vbox.addLayout(self.hbox3)
        self.vbox.addWidget(self.chanlunLogMonitor)
        self.setLayout(self.vbox)

        self.codeEdit.returnPressed.connect(self.updateSymbol)

    #-----------------------------------------------------------------------
    #从通联数据端获取历史数据
    def downloadData(self, symbol, unit):
        listBar = [] #K线数据
        num = 0

        #从通联客户端获取K线数据
        historyDataEngine = HistoryDataEngine()

        # unit为int型获取分钟数据，为String类型获取日周月K线数据
        if type(unit) is types.IntType:
            #从通联数据端获取当日分钟数据并存入数据库
            historyDataEngine.downloadFuturesIntradayBar(symbol, unit)
            # 从数据库获取前几天的分钟数据
            cx = self.getDbData(symbol, unit)
            if cx:
                for data in cx:
                    barOpen = data['open']
                    barClose = data['close']
                    barLow = data['low']
                    barHigh = data['high']
                    barTime = data['datetime']
                    listBar.append((num, barTime, barOpen, barClose, barLow, barHigh))
                    num += 1

        elif type(unit) is types.StringType:
            data = historyDataEngine.downloadFuturesBar(symbol, unit)
            if data:
                for d in data:
                    barOpen = d.get('openPrice', 0)
                    barClose = d.get('closePrice', 0)
                    barLow = d.get('lowestPrice', 0)
                    barHigh = d.get('highestPrice', 0)
                    if unit == "daily":
                        barTime = d.get('tradeDate', '').replace('-', '')
                    else:
                        barTime = d.get('endDate', '').replace('-', '')
                    listBar.append((num, barTime, barOpen, barClose, barLow, barHigh))
                    num += 1
                if unit == "monthly" or unit == "weekly":
                    listBar.reverse()
        else:
            print "参数格式错误"
            return

        #将List数据转换成dataFormat类型，方便处理
        df = pd.DataFrame(listBar, columns=['num', 'time', 'open', 'close', 'low', 'high'])
        df.index = df['time'].tolist()
        df = df.drop('time', 1)
        return df
    #-----------------------------------------------------------------------
    #从数据库获取前两天的分钟数据
    def getDbData(self, symbol, unit):
        #周六周日不交易，无分钟数据
        # 给数据库命名
        dbname = ''
        days = 7
        if unit == 1:
            dbname = MINUTE_DB_NAME
        elif unit == 5:
            dbname = MINUTE5_DB_NAME
        elif unit == 15:
            dbname = MINUTE15_DB_NAME
        elif unit == 30:
            dbname = MINUTE30_DB_NAME
        elif unit == 60:
            dbname = MINUTE60_DB_NAME

        weekday = datetime.now().weekday()  # weekday() 返回的是0-6是星期一到星期日
        if days == 2:
            if weekday == 6:
                aDay = timedelta(days=3)
            elif weekday == 0 or weekday == 1:
                aDay = timedelta(days=4)
            else:
                aDay = timedelta(days=2)
        else:
            aDay = timedelta(days=7)

        startDate = (datetime.now() - aDay).strftime('%Y%m%d')
        print startDate
        if self.__mongoConnected:
            collection = self.__mongoConnection[dbname][symbol]
            cx = collection.find({'date': {'$gte': startDate}})
            return cx
        else:
            return None
    #----------------------------------------------------------------------------------
    #"""合约变化"""
    def updateSymbol(self):
        # 读取组件数据
        instrumentid = str(self.codeEdit.text())

        self.chanlunEngine.writeChanlunLog(u'查询合约%s' % (instrumentid))

        # 从通联数据客户端获取当日分钟数据
        self.data = self.downloadData(instrumentid, 1)

        if self.data.empty:
            self.chanlunEngine.writeChanlunLog(u'合约%s 不存在' % (instrumentid))
        else:
            if self.tickLoaded:
                self.vbox1.removeWidget(self.TickW)
                self.TickW.deleteLater()
            else:
                self.vbox1.removeWidget(self.PriceW)
                self.PriceW.deleteLater()

            self.PriceW = PriceWidget(self.eventEngine, self.chanlunEngine, self.data)
            self.vbox1.addWidget(self.PriceW)
            # 画K线图
            self.PriceW.plotHistorticData()

            self.chanlunEngine.writeChanlunLog(u'打开合约%s 1分钟K线图' % (instrumentid))

            self.penLoaded = False
            self.segmentLoaded = False
            self.tickLoaded = False
            self.zhongShuLoaded = False

            # # 订阅合约[仿照ctaEngine.py写的]
            # # 先取消订阅之前的合约，再订阅最新输入的合约
            # contract = self.mainEngine.getContract(self.instrumentid)
            # if contract:
            #     req = VtSubscribeReq()
            #     req.symbol = contract.symbol
            #     self.mainEngine.unsubscribe(req, contract.gatewayName)
            #
            #     contract = self.mainEngine.getContract(instrumentid)
            #     if contract:
            #         req = VtSubscribeReq()
            #         req.symbol = contract.symbol
            #         self.mainEngine.subscribe(req, contract.gatewayName)
            #     else:
            #         self.chanlunEngine.writeChanlunLog(u'交易合约%s无法找到' % (instrumentid))
            #
            # # 重新注册事件监听
            # self.eventEngine.unregister(EVENT_TICK + self.instrumentid, self.signal.emit)
            # self.eventEngine.register(EVENT_TICK + instrumentid, self.signal.emit)

            # 更新目前的合约
            self.instrumentid = instrumentid

    def oneM(self):
        "打开1分钟K线图"
        self.chanlunEngine.writeChanlunLog(u'打开合约%s 1分钟K线图' % (self.instrumentid))
        # 从通联数据客户端获取数据
        self.data = self.downloadData(self.instrumentid, 1)

        if self.tickLoaded:
            self.vbox1.removeWidget(self.TickW)
            self.TickW.deleteLater()
        else:
            self.vbox1.removeWidget(self.PriceW)
            self.PriceW.deleteLater()

        self.PriceW = PriceWidget(self.eventEngine, self.chanlunEngine, self.data)
        self.vbox1.addWidget(self.PriceW)

        # 画K线图
        self.PriceW.plotHistorticData()

        self.tickLoaded = False
        self.penLoaded = False
        self.segmentLoaded = False
        self.zhongShuLoaded = False

    # ----------------------------------------------------------------------
    def fiveM(self):
        "打开5分钟K线图"
        self.chanlunEngine.writeChanlunLog(u'打开合约%s 5分钟K线图' % (self.instrumentid))

        # 从通联数据客户端获取数据
        self.data = self.downloadData(self.instrumentid, 5)

        if self.tickLoaded:
            self.vbox1.removeWidget(self.TickW)
            self.TickW.deleteLater()
        else:
            self.vbox1.removeWidget(self.PriceW)
            self.PriceW.deleteLater()

        self.PriceW = PriceWidget(self.eventEngine, self.chanlunEngine, self.data)
        self.vbox1.addWidget(self.PriceW)

        # 画K线图
        self.PriceW.plotHistorticData()

        self.tickLoaded = False
        self.penLoaded = False
        self.segmentLoaded = False
        self.zhongShuLoaded = False

    # ----------------------------------------------------------------------
    def fifteenM(self):
        "打开15分钟K线图"
        self.chanlunEngine.writeChanlunLog(u'打开合约%s 15分钟K线图' % (self.instrumentid))

        # 从通联数据客户端获取数据
        self.data = self.downloadData(self.instrumentid, 15)

        if self.tickLoaded:
            self.vbox1.removeWidget(self.TickW)
            self.TickW.deleteLater()
        else:
            self.vbox1.removeWidget(self.PriceW)
            self.PriceW.deleteLater()

        self.PriceW = PriceWidget(self.eventEngine, self.chanlunEngine, self.data)
        self.vbox1.addWidget(self.PriceW)

        # 画K线图
        self.PriceW.plotHistorticData()

        self.tickLoaded = False
        self.penLoaded = False
        self.segmentLoaded = False
        self.zhongShuLoaded = False

    # ----------------------------------------------------------------------
    def thirtyM(self):
        "打开30分钟K线图"
        self.chanlunEngine.writeChanlunLog(u'打开合约%s 30分钟K线图' % (self.instrumentid))
        # 从通联数据客户端获取数据
        self.data = self.downloadData(self.instrumentid, 30)

        if self.tickLoaded:
            self.vbox1.removeWidget(self.TickW)
            self.TickW.deleteLater()
        else:
            self.vbox1.removeWidget(self.PriceW)
            self.PriceW.deleteLater()

        self.PriceW = PriceWidget(self.eventEngine, self.chanlunEngine, self.data)
        self.vbox1.addWidget(self.PriceW)

        # 画K线图
        self.PriceW.plotHistorticData()

        self.tickLoaded = False
        self.penLoaded = False
        self.segmentLoaded = False
        self.zhongShuLoaded = False

    # ----------------------------------------------------------------------
    def sixtyM(self):
        "打开60分钟K线图"
        self.chanlunEngine.writeChanlunLog(u'打开合约%s 60分钟K线图' % (self.instrumentid))
        # 从通联数据客户端获取数据
        self.data = self.downloadData(self.instrumentid, 60)

        if self.tickLoaded:
            self.vbox1.removeWidget(self.TickW)
            self.TickW.deleteLater()
        else:
            self.vbox1.removeWidget(self.PriceW)
            self.PriceW.deleteLater()

        self.PriceW = PriceWidget(self.eventEngine, self.chanlunEngine, self.data)
        self.vbox1.addWidget(self.PriceW)

        # 画K线图
        self.PriceW.plotHistorticData()

        self.tickLoaded = False
        self.penLoaded = False
        self.segmentLoaded = False
        self.zhongShuLoaded = False

    # ----------------------------------------------------------------------
    def daily(self):
        """打开日K线图"""
        self.chanlunEngine.writeChanlunLog(u'打开合约%s 日K线图' % (self.instrumentid))
        # 从通联数据客户端获取数据
        self.data = self.downloadData(self.instrumentid, "daily")

        if self.tickLoaded:
            self.vbox1.removeWidget(self.TickW)
            self.TickW.deleteLater()
        else:
            self.vbox1.removeWidget(self.PriceW)
            self.PriceW.deleteLater()

        self.PriceW = PriceWidget(self.eventEngine, self.chanlunEngine, self.data)
        self.vbox1.addWidget(self.PriceW)

        # 画K线图
        self.PriceW.plotHistorticData()

        self.tickLoaded = False
        self.penLoaded = False
        self.segmentLoaded = False
        self.zhongShuLoaded = False

    # ----------------------------------------------------------------------
    def weekly(self):
        """打开周K线图"""
        self.chanlunEngine.writeChanlunLog(u'打开合约%s 周K线图' % (self.instrumentid))
        # 从通联数据客户端获取数据
        self.data = self.downloadData(self.instrumentid, "weekly")

        if self.tickLoaded:
            self.vbox1.removeWidget(self.TickW)
            self.TickW.deleteLater()
        else:
            self.vbox1.removeWidget(self.PriceW)
            self.PriceW.deleteLater()

        self.PriceW = PriceWidget(self.eventEngine, self.chanlunEngine, self.data)
        self.vbox1.addWidget(self.PriceW)

        # 画K线图
        self.PriceW.plotHistorticData()

        self.tickLoaded = False
        self.penLoaded = False
        self.segmentLoaded = False
        self.zhongShuLoaded = False

    def monthly(self):
        """打开月K线图"""
        self.chanlunEngine.writeChanlunLog(u'打开合约%s 月K线图' % (self.instrumentid))
        # 从通联数据客户端获取数据并画图
        self.data = self.downloadData(self.instrumentid, "monthly")

        if self.tickLoaded:
            self.vbox1.removeWidget(self.TickW)
            self.TickW.deleteLater()
        else:
            self.vbox1.removeWidget(self.PriceW)
            self.PriceW.deleteLater()

        self.PriceW = PriceWidget(self.eventEngine, self.chanlunEngine, self.data)
        self.vbox1.addWidget(self.PriceW)

        # 画K线图
        self.PriceW.plotHistorticData()

        self.tickLoaded = False
        self.penLoaded = False
        self.segmentLoaded = False
        self.zhongShuLoaded = False
    # ----------------------------------------------------------------------
    def openTick(self):
        """切换成tick图"""
        self.chanlunEngine.writeChanlunLog(u'打开tick图')

        self.vbox1.removeWidget(self.PriceW)
        self.PriceW.deleteLater()
        self.TickW = TickWidget(self.eventEngine, self.chanlunEngine)
        self.vbox1.addWidget(self.TickW)

        self.tickLoaded = True
        self.penLoaded = False
        self.segmentLoaded = False
        self.zhongShuLoaded = False

    # ----------------------------------------------------------------------
    def restore(self):
        """还原初始k线状态"""
        self.chanlunEngine.writeChanlunLog(u'还原加载成功')
        if self.tickLoaded:
            self.vbox1.removeWidget(self.TickW)
            self.TickW.deleteLater()
        else:
            self.vbox1.removeWidget(self.PriceW)
            self.PriceW.deleteLater()

        self.data = self.downloadData(self.instrumentid, 1)
        self.PriceW = PriceWidget(self.eventEngine, self.chanlunEngine, self.data, self)
        self.vbox1.addWidget(self.PriceW)

        # 画K线图
        self.PriceW.plotHistorticData()

        self.chanlunEngine.writeChanlunLog(u'还原为1分钟k线图')
        self.penLoaded = False
        self.segmentLoaded = False
        self.tickLoaded = False

    # ----------------------------------------------------------------------
    def pen(self):
        """加载分笔"""
        # 先合并K线数据,记录新建PriceW之前合并K线的数据
        if not self.penLoaded:
            after_fenxing = self.judgeInclude() #判断self.data中K线数据的包含关系

            # 清空画布时先remove已有的Widget再新建
            self.vbox1.removeWidget(self.PriceW)
            self.PriceW.deleteLater()
            self.PriceW = PriceWidget(self.eventEngine, self.chanlunEngine, after_fenxing)
            self.vbox1.addWidget(self.PriceW)

            #使用合并K线的数据重新画K线图
            self.plotAfterFenXing(after_fenxing)
            # 找出顶和底
            fenxing_data, fenxing_type = self.findTopAndLow(after_fenxing)

            arrayFenxingdata = np.array(fenxing_data)
            arrayTypedata = np.array(fenxing_type)
            self.fenY = []
            self.fenX = [m[0] for m in arrayFenxingdata]
            fenbiY1 = [m[4] for m in arrayFenxingdata]  # 顶分型标志最高价
            fenbiY2 = [m[3] for m in arrayFenxingdata]  # 底分型标志最低价
            for i in xrange(len(self.fenX)):
                if arrayTypedata[i] == 1:
                    self.fenY.append(fenbiY1[i])
                else:
                    self.fenY.append(fenbiY2[i])
            if not self.penLoaded:
                if self.fenX:
                    self.fenX.append(self.fenX[-1])
                    self.fenY.append(self.fenY[-1])
                    print "self.fenX: ", self.fenX
                    print "self.fenY: ", self.fenY
                    self.fenbi(self.fenX, self.fenY)
                    self.fenX.pop()
                    self.fenY.pop()

            self.chanlunEngine.writeChanlunLog(u'分笔加载成功')
            self.penLoaded = True
    # ----------------------------------------------------------------------
    def segment(self):
        if not self.penLoaded:
            self.pen()                #先分笔才能分段
        segmentX = []    #分段点X轴值
        segmentY = []    #分段点Y轴值
        temp_type = 0    #标志线段方向，向上为1，向下为-1, 未判断前三笔是否重合为0
        i = 0
        while i < len(self.fenX) - 4:
            if temp_type == 0:
                if self.fenY[i] > self.fenY[i+1] and self.fenY[i] > self.fenY[i+3]:
                    temp_type = -1           #向下线段，三笔重合
                    segmentX.append(self.fenX[i])
                    segmentY.append(self.fenY[i])
                elif self.fenY[i] < self.fenY[i+1] and self.fenY[i] < self.fenY[i+3]:
                    temp_type = 1            #向上线段，三笔重合
                    segmentX.append(self.fenX[i])
                    segmentY.append(self.fenY[i])
                else:
                    temp_type = 0
                    i += 1
                    continue
            if temp_type == 1:  #向上线段
                j = i+1
                high = []  # 记录顶
                low = []  # 记录低
                while j < len(self.fenX) - 1:     #记录顶底
                    high.append(self.fenY[j])
                    low.append(self.fenY[j+1])
                    j += 2
                if self.fenY[i+4] < self.fenY[i+1]:    #向上线段被向下笔破坏
                    j = 0
                    while j < len(high)-2:
                        # 顶底出现顶分型，向上线段结束
                        if high[j+1] > high[j] and high[j+1] > high[j+2]:
                            num = i + 2 * j + 3   #线段结束点位置
                            segmentX.append(self.fenX[num])
                            segmentY.append(self.fenY[num])
                            i = num
                            temp_type = -1   #向上线段一定由向下线段结束
                            break
                        j += 1
                    if j == len(high)-2:
                        break
                else:   #向上线段未被向下笔破坏
                    j = 1
                    while j < len(high)-2:
                        # 顶底出现底分型，向上线段结束
                        if low[j + 1] < low[j] and low[j + 1] < low[j + 2]:
                            num = i + 2 * j + 1  # 线段结束点位置
                            segmentX.append(self.fenX[num])
                            segmentY.append(self.fenY[num])
                            i = num
                            temp_type = -1  # 向上线段一定由向下线段结束
                            break
                        j += 1
                    if j == len(high)-2:
                        break
            elif temp_type == -1:  # 向下线段
                j = i + 1
                high = []  # 记录顶
                low = []  # 记录低
                while j < len(self.fenX) - 1:  # 记录顶底
                    high.append(self.fenY[j + 1])
                    low.append(self.fenY[j])
                    j += 2
                if self.fenY[i + 4] > self.fenY[i + 1]:  # 向下线段被向上笔破坏
                    j = 0
                    while j < len(high) - 2:
                        # 顶底出现底分型，向下线段结束
                        if low[j + 1] < low[j] and low[j + 1] < low[j + 2]:
                            num = i + 2 * j + 3  # 线段结束点位置
                            segmentX.append(self.fenX[num])
                            segmentY.append(self.fenY[num])
                            i = num
                            temp_type = 1  # 向下线段一定由向上线段结束
                            break
                        j += 1
                    if j == len(high) - 2:
                        break
                else:  # 向下线段未被向上笔破坏
                    j = 1
                    while j < len(high) - 2:
                    # 顶底出现顶分型，向下线段结束
                        if high[j + 1] > high[j] and high[j + 1] > high[j + 2]:
                            num = i + 2 * j + 1  # 线段结束点位置
                            segmentX.append(self.fenX[num])
                            segmentY.append(self.fenY[num])
                            i = num
                            temp_type = 1  # 向下线段一定由向上线段结束
                            break
                        j += 1
                    if j == len(high) - 2:
                        break
        print "segmentX: ", segmentX
        print "segmentY: ", segmentY
        if not self.segmentLoaded:
            if len(segmentX) > 1:
                segmentX.append(segmentX[-1])
                segmentY.append(segmentY[-1])
                segmentX = [int(x) for x in segmentX]
                segmentY = [int(y) for y in segmentY]
                self.fenduan(segmentX, segmentY)
        self.chanlunEngine.writeChanlunLog(u'分段加载成功')
        self.segmentLoaded = True
    # ----------------------------------------------------------------------
    def updateChanlunLog(self, event):
        """更新缠论相关日志"""
        log = event.dict_['data']
        # print type(log)
        if(log.logTime):
            content = '\t'.join([log.logTime, log.logContent])
            self.chanlunLogMonitor.append(content)
        else:
            print 0
    #-----------------------------------------------------------------------
    def zhongShu(self):
        if not self.penLoaded:
            self.pen()  # 先分笔才能画走势中枢
        # temp_type = 0  # 标志中枢方向，向上为1，向下为-1
        i = 0
        temp_high, temp_low = 0, 0
        minX, maxY = 0, 0
        self.zhongshuPos = []  # 记录所有的中枢开始段和结束段的位置
        self.zhongShuType = [] #记录所有中枢的方向
        while i < len(self.fenX) - 4:
            if (self.fenY[i] > self.fenY[i + 1] and self.fenY[i + 1] < self.fenY[i + 4]): #判断进入段方向
                temp_low = max(self.fenY[i + 1], self.fenY[i + 3])
                temp_high = min(self.fenY[i + 2], self.fenY[i + 4])   #记录中枢内顶的最小值与底的最大值
                minX = self.fenX[i+1]
                self.zhongshuPos.append(i)
                self.zhongShuType.append(-1)
                j = i
                while i < len(self.fenX) - 4:
                    j = i
                    if self.fenY[i + 1] < self.fenY[i + 4] and self.fenY[i + 4] > temp_low and self.fenY[i + 3] < temp_high :
                        maxX = self.fenX[i+4]
                        if self.fenY[i + 3] > temp_low:
                            temp_low = self.fenY[i + 3]
                        if self.fenY[i + 4] < temp_high:
                            temp_high = self.fenY[i + 4]
                        i = i + 1
                    elif self.fenY[i + 1] > self.fenY[i + 4] and self.fenY[i + 4] < temp_high and self.fenY[i + 3] > temp_low :
                        maxX = self.fenX[i + 4]
                        if self.fenY[i + 3] < temp_high:
                            temp_high = self.fenY[i + 3]
                        if self.fenY[i + 4] > temp_low:
                            temp_low = self.fenY[i + 4]
                        i = i + 1
                    if j == i:
                        break
            elif (self.fenY[i] < self.fenY[i + 1] and self.fenY[i + 1] > self.fenY[i + 4]):
                temp_high = min(self.fenY[i + 1], self.fenY[i + 3])
                temp_low = max(self.fenY[i + 2], self.fenY[i + 4])
                minX = self.fenX[i + 1]
                self.zhongshuPos.append(i)
                self.zhongShuType.append(1)
                j = i
                while i < len(self.fenX) - 4:
                    j = i
                    if self.fenY[i + 1] > self.fenY[i + 4] and self.fenY[i + 4] < temp_high and self.fenY[i + 3] > temp_low:
                        maxX = self.fenX[i + 4]
                        if self.fenY[i + 3] < temp_high:
                            temp_high = self.fenY[i + 3]
                        if self.fenY[i + 4] > temp_low:
                            temp_low = self.fenY[i + 4]
                        i = i + 1
                    elif self.fenY[i + 1] < self.fenY[i + 4] and self.fenY[i + 4] > temp_low and self.fenY[i + 3] < temp_high:
                        maxX = self.fenX[i + 4]
                        if self.fenY[i + 3] > temp_low:
                            temp_low = self.fenY[i + 3]
                        if self.fenY[i + 4] < temp_high:
                            temp_high = self.fenY[i + 4]
                        i = i + 1
                    if i == j:
                        break
            else:
                i += 1
                continue

            # 画出当前判断出的中枢
            if minX != 0 and maxX == 0:
                maxX = self.fenX[i+4]
                i = i + 1
                self.zhongshuPos.append(i + 4)
            else:
                self.zhongshuPos.append(i + 3)

            minY, maxY = temp_low, temp_high

            print minX, minY, maxX, maxY
            if int(maxY) > int(minY):
                plotX = [minX, minX, maxX, maxX, minX]
                plotY = [minY, maxY, maxY, minY, minY]
                plotX = [int(x) for x in plotX]
                plotY = [int(y) for y in plotY]
                self.zhongshu(plotX, plotY)

            i = i + 4

        self.zhongShuLoaded = True
        self.chanlunEngine.writeChanlunLog(u'走势中枢加载成功')

     # ----------------------------------------------------------------------
    def shop(self):
        """加载买卖点"""
        if not self.zhongShuLoaded:
            self.zhongShu()
        i = 0
        while i < len(self.zhongShuType) - 1:
            startPos, endPos = self.zhongshuPos[2*i], self.zhongshuPos[2*i + 1]  # 中枢开始段的位置和结束段的位置

            startY = self.fenY[startPos + 1] - self.fenY[startPos]  # 开始段Y轴距离
            startX = self.fenX[startPos + 1] - self.fenX[startPos]  # 开始段X轴距离
            startK = abs(startY * startX)  # 开始段投影面积

            endY = self.fenY[endPos + 1] - self.fenY[endPos]  # 结束段Y轴距离
            endX = self.fenX[endPos + 1] - self.fenX[endPos]  # 结束段段X轴距离
            endK = abs(endY * endX)  # 开始段投影面积

            if endK < startK:
                print startPos, endPos
                if self.zhongShuType[i] == 1 and self.zhongShuType[i + 1] == -1:
                    # 一卖
                    self.sellpoint([self.fenX[endPos + 1]], [self.fenY[endPos + 1]], 1)
                    # 二卖，一卖后一个顶点
                    self.sellpoint([self.fenX[endPos + 3]], [self.fenY[endPos + 3]], 2)
                    # 三卖，一卖之后中枢结束段的第一个顶
                    i = i + 1
                    nextPos = self.zhongshuPos[2*i + 1]  # 下一个中枢结束位置
                    if nextPos + 1 < len(self.fenY):
                        if self.fenY[nextPos + 1] > self.fenY[nextPos]:
                            self.sellpoint([self.fenX[nextPos + 1]], [self.fenY[nextPos + 1]], 3)
                        else:
                            self.sellpoint([self.fenX[nextPos]], [self.fenY[nextPos]], 3)
                elif self.zhongShuType[i] == -1 and self.zhongShuType[i + 1] == 1:
                    # 一买
                    self.buypoint([self.fenX[endPos + 1]], [self.fenY[endPos + 1]], 1)
                    # 二买，一买后一个底点
                    self.buypoint([self.fenX[endPos + 3]], [self.fenY[endPos + 3]], 2)
                    # 三买，一买之后中枢结束段的第一个顶
                    i = i + 1
                    nextPos = self.zhongshuPos[2*i + 1]  # 下一个中枢结束位置
                    if nextPos + 1 < len(self.fenY):
                        if self.fenY[nextPos + 1] < self.fenY[nextPos]:
                            self.buypoint([self.fenX[nextPos + 1]], [self.fenY[nextPos + 1]], 3)
                        else:
                            self.buypoint([self.fenX[nextPos]], [self.fenY[nextPos]], 3)

            i = i + 1           # 接着判断之后的中枢是否出现背驰

        self.chanlunEngine.writeChanlunLog(u'买卖点加载成功')
    # ----------------------------------------------------------------------
    def fenbi(self, fenbix, fenbiy):
        self.PriceW.pw2.plotItem.plot(x=fenbix, y=fenbiy, pen=QtGui.QPen(QtGui.QColor(255, 236, 139)))

    def fenduan(self, fenduanx, fenduany):
        self.PriceW.pw2.plot(x=fenduanx, y=fenduany, symbol='o', pen=QtGui.QPen(QtGui.QColor(131, 111, 255)))

    def zhongshu(self, zhongshux, zhongshuy):
        self.PriceW.pw2.plot(x=zhongshux, y=zhongshuy, pen=QtGui.QPen(QtGui.QColor(255,165,0)))

    def buypoint(self, buyx, buyy, point):
        if point == 1:
            self.PriceW.pw2.plot(x=buyx, y=buyy, symbolSize=18, symbolBrush=(255,0,0), symbolPen=(255,0,0), symbol='star')
        elif point == 2:
            self.PriceW.pw2.plot(x=buyx, y=buyy, symbolSize=18, symbolBrush=(238,130,238), symbolPen=(238,130,238),symbol='star')
        elif point == 3:
            self.PriceW.pw2.plot(x=buyx, y=buyy, symbolSize=18, symbolBrush=(138,43,226), symbolPen=(138,43,226),symbol='star')

    def sellpoint(self, sellx, selly, point):
        if point == 1:
            self.PriceW.pw2.plot(x=sellx, y=selly,  symbolSize=18, symbolBrush=(119,172,48), symbolPen=(119,172,48), symbol='star')
        elif point == 2:
                self.PriceW.pw2.plot(x=sellx, y=selly, symbolSize=18, symbolBrush=(221,221,34), symbolPen=(221,221,34),symbol='star')
        elif point == 3:
            self.PriceW.pw2.plot(x=sellx, y=selly, symbolSize=18, symbolBrush=(179,158,77), symbolPen=(179,158,77),symbol='star')

    # ----------------------------------------------------------------------
    # 判断包含关系，仿照聚框，合并K线数据
    def judgeInclude(self):
        ## 判断包含关系
        k_data = self.data
        # 保存分型后dataFrame的值
        after_fenxing = pd.DataFrame()
        temp_data = k_data[:1]
        zoushi = [3]  # 3-持平 4-向下 5-向上
        for i in xrange(len(k_data)):
            case1 = temp_data.high[-1] >= k_data.high[i] and temp_data.low[-1] <= k_data.low[i]  # 第1根包含第2根
            case2 = temp_data.high[-1] <= k_data.high[i] and temp_data.low[-1] >= k_data.low[i]  # 第2根包含第1根
            case3 = temp_data.high[-1] == k_data.high[i] and temp_data.low[-1] == k_data.low[i]  # 第1根等于第2根
            case4 = temp_data.high[-1] > k_data.high[i] and temp_data.low[-1] > k_data.low[i]  # 向下趋势
            case5 = temp_data.high[-1] < k_data.high[i] and temp_data.low[-1] < k_data.low[i]  # 向上趋势
            if case3:
                zoushi.append(3)
                continue
            elif case1:
                print temp_data
                if zoushi[-1] == 4:
                    temp_data.ix[0, 4] = k_data.high[i]  #向下走取高点的低点
                else:
                    temp_data.ix[0, 3] = k_data.low[i]   #向上走取低点的高点

            elif case2:
                temp_temp = temp_data[-1:]
                temp_data = k_data[i:i + 1]
                if zoushi[-1] == 4:
                    temp_data.ix[0, 4] = temp_temp.high[0]
                else:
                    temp_data.ix[0, 3] = temp_temp.low[0]

            elif case4:
                zoushi.append(4)
                after_fenxing = pd.concat([after_fenxing, temp_data], axis=0)
                temp_data = k_data[i:i + 1]

            elif case5:
                zoushi.append(5)
                after_fenxing = pd.concat([after_fenxing, temp_data], axis=0)
                temp_data = k_data[i:i + 1]

        return after_fenxing

    # ----------------------------------------------------------------------
    #画出合并后的K线图，分笔
    def plotAfterFenXing(self, after_fenxing):
        #判断包含关系，合并K线
        for i in xrange(len(after_fenxing)):
            #处理k线的最大最小值、开盘收盘价，合并后k线不显示影线。
            after_fenxing.iloc[i, 0] = i
            if after_fenxing.open[i] > after_fenxing.close[i]:
                after_fenxing.iloc[i, 1] = after_fenxing.high[i]
                after_fenxing.iloc[i, 2] = after_fenxing.low[i]
            else:
                after_fenxing.iloc[i, 1] = after_fenxing.low[i]
                after_fenxing.iloc[i, 2] = after_fenxing.high[i]
            self.PriceW.onBarAfterFenXing(i, after_fenxing.index[i], after_fenxing.open[i], after_fenxing.close[i], after_fenxing.low[i], after_fenxing.high[i])
        self.PriceW.plotKlineAfterFenXing()
        print "plotKLine after fenxing"

    # ----------------------------------------------------------------------
    # 找出顶和底
    def findTopAndLow(self, after_fenxing):
        temp_num = 0  # 上一个顶或底的位置
        temp_high = 0  # 上一个顶的high值
        temp_low = 0  # 上一个底的low值
        temp_type = 0  # 上一个记录位置的类型
        i = 1
        fenxing_type = []  # 记录分型点的类型，1为顶分型，-1为底分型
        fenxing_data = pd.DataFrame() # 分型点的DataFrame值
        while (i < len(after_fenxing) - 1):
            case1 = after_fenxing.high[i - 1] < after_fenxing.high[i] and after_fenxing.high[i] > after_fenxing.high[i + 1]  # 顶分型
            case2 = after_fenxing.low[i - 1] > after_fenxing.low[i] and after_fenxing.low[i] < after_fenxing.low[i + 1]  # 底分型
            if case1:
                if temp_type == 1:  # 如果上一个分型为顶分型，则进行比较，选取高点更高的分型
                    if after_fenxing.high[i] <= temp_high:
                        i += 1
                    else:
                        temp_high = after_fenxing.high[i]
                        temp_num = i
                        temp_type = 1
                        i += 1
                elif temp_type == 2:  # 如果上一个分型为底分型，则记录上一个分型，用当前分型与后面的分型比较，选取同向更极端的分型
                    if temp_low >= after_fenxing.high[i]:  # 如果上一个底分型的底比当前顶分型的顶高，则跳过当前顶分型。
                        i += 1
                    elif i < temp_num + 4:  # 顶和底至少5k线
                        i += 1
                    else:
                        fenxing_type.append(-1)
                        fenxing_data = pd.concat([fenxing_data, after_fenxing[temp_num:temp_num + 1]], axis=0)
                        temp_high = after_fenxing.high[i]
                        temp_num = i
                        temp_type = 1
                        i += 1
                else:
                    temp_high = after_fenxing.high[i]
                    temp_num = i
                    temp_type = 1
                    i += 1

            elif case2:
                if temp_type == 2:  # 如果上一个分型为底分型，则进行比较，选取低点更低的分型
                    if after_fenxing.low[i] >= temp_low:
                        i += 1
                    else:
                        temp_low = after_fenxing.low[i]
                        temp_num = i
                        temp_type = 2
                        i += 1
                elif temp_type == 1:  # 如果上一个分型为顶分型，则记录上一个分型，用当前分型与后面的分型比较，选取同向更极端的分型
                    if temp_high <= after_fenxing.low[i]:  # 如果上一个顶分型的底比当前底分型的底低，则跳过当前底分型。
                        i += 1
                    elif i < temp_num + 4:  # 顶和底至少5k线
                        i += 1
                    else:
                        fenxing_type.append(1)
                        fenxing_data = pd.concat([fenxing_data, after_fenxing[temp_num:temp_num + 1]], axis=0)
                        temp_low = after_fenxing.low[i]
                        temp_num = i
                        temp_type = 2
                        i += 1
                else:
                    temp_low = after_fenxing.low[i]
                    temp_num = i
                    temp_type = 2
                    i += 1
            else:
                i += 1

        # if fenxing_type:
        #     if fenxing_type[-1] == 1 and temp_type == 2:
        #         fenxing_type.append(-1)
        #         fenxing_data = pd.concat([fenxing_data, after_fenxing[temp_num:temp_num + 1]], axis=0)
        #
        #     if fenxing_type[-1] == -1 and temp_type == 1:
        #         fenxing_type.append(1)
        #         fenxing_data = pd.concat([fenxing_data, after_fenxing[temp_num:temp_num + 1]], axis=0)

        return fenxing_data, fenxing_type

    # ----------------------------------------------------------------------
    # 连接MongoDB数据库
    def __connectMongo(self):
        try:
            self.__mongoConnection = pymongo.MongoClient("localhost", 27017)
            self.__mongoConnected = True
        except ConnectionFailure:
            pass
    # ----------------------------------------------------------------------
    def registerEvent(self):
        """注册事件监听"""
        self.signal.connect(self.updateChanlunLog)
        self.eventEngine.register(EVENT_CHANLUN_LOG, self.signal.emit)

########################################################################
class PriceWidget(QtGui.QWidget):
    """用于显示价格走势图"""
    signal = QtCore.pyqtSignal(type(Event()))
    symbol = ''

    class CandlestickItem(pg.GraphicsObject):
        def __init__(self, data):
            pg.GraphicsObject.__init__(self)
            self.data = data  ## data must have fields: time, open, close, min, max
            self.generatePicture()

        def generatePicture(self):
            ## pre-computing a QPicture object allows paint() to run much more quickly,
            ## rather than re-drawing the shapes every time.
            self.picture = QtGui.QPicture()
            p = QtGui.QPainter(self.picture)
            p.setPen(pg.mkPen(color='w', width=0.4))  # 0.4 means w*2
            # w = (self.data[1][0] - self.data[0][0]) / 3.
            w = 0.2
            for (n, t, open, close, min, max) in self.data:
                p.drawLine(QtCore.QPointF(n, min), QtCore.QPointF(n, max))
                if open > close:
                    p.setBrush(pg.mkBrush('g'))
                else:
                    p.setBrush(pg.mkBrush('r'))
                p.drawRect(QtCore.QRectF(n-w, open, w*2, close-open))
                pg.setConfigOption('leftButtonPan', False)
            p.end()

        def paint(self, p, *args):
            p.drawPicture(0, 0, self.picture)

        def boundingRect(self):
            ## boundingRect _must_ indicate the entire area that will be drawn on
            ## or else we will get artifacts and possibly crashing.
            ## (in this case, QPicture does all the work of computing the bouning rect for us)
            return QtCore.QRectF(self.picture.boundingRect())

    #----------------------------------------------------------------------
    def __init__(self, eventEngine, chanlunEngine, data, parent=None):
        """Constructor"""
        super(PriceWidget, self).__init__(parent)

        # K线图EMA均线的参数、变量
        self.EMAFastAlpha = 0.0167  # 快速EMA的参数,60
        self.EMASlowAlpha = 0.0083  # 慢速EMA的参数,120
        self.fastEMA = 0  # 快速EMA的数值
        self.slowEMA = 0  # 慢速EMA的数值
        self.listfastEMA = []
        self.listslowEMA = []

        # 保存K线数据的列表对象
        self.listBar = []
        self.listClose = []
        self.listHigh = []
        self.listLow = []
        self.listOpen = []

        # 是否完成了历史数据的读取
        self.initCompleted = False

        self.__eventEngine = eventEngine
        self.__chanlunEngine = chanlunEngine
        self.data = data  #画图所需数据
        # MongoDB数据库相关
        self.__mongoConnected = False
        self.__mongoConnection = None

        # 调用函数
        self.__connectMongo()
        self.initUi()
        # self.registerEvent()

    #----------------------------------------------------------------------
    def initUi(self):
        """初始化界面"""
        self.setWindowTitle(u'Price')

        self.vbl_1 = QtGui.QHBoxLayout()

        self.initplotKline()  # plotKline初始化

        self.setLayout(self.vbl_1)

    #----------------------------------------------------------------------
    def initplotKline(self):
        """Kline"""
        s = self.data.index  #横坐标值
        print "numbers of KLine: ", len(s)
        xdict = dict(enumerate(s))
        self.__axisTime = MyStringAxis(xdict, orientation='bottom')
        self.pw2 = pg.PlotWidget(axisItems={'bottom': self.__axisTime})  # K线图
        pw2x = self.pw2.getAxis('bottom')
        pw2x.setGrid(150)  # 设置默认x轴网格
        pw2y = self.pw2.getAxis('left')
        pw2y.setGrid(150)  # 设置默认y轴网格
        self.vbl_1.addWidget(self.pw2)
        self.pw2.setMinimumWidth(1500)
        self.pw2.setMaximumWidth(1800)
        self.pw2.setDownsampling(mode='peak')
        self.pw2.setClipToView(True)

        self.curve5 = self.pw2.plot()
        self.curve6 = self.pw2.plot()

        self.candle = self.CandlestickItem(self.listBar)
        self.pw2.addItem(self.candle)
        ## Draw an arrowhead next to the text box
        # self.arrow = pg.ArrowItem()
        # self.pw2.addItem(self.arrow)

    # 从数据库读取一分钟数据画分钟线
    def plotMin(self, symbol):
        self.initCompleted = True
        cx = self.__mongoMinDB[symbol].find()
        print cx.count()
        if cx:
            for data in cx:
                self.barOpen = data['open']
                self.barClose = data['close']
                self.barLow = data['low']
                self.barHigh = data['high']
                self.barOpenInterest = data['openInterest']
                # print self.num, self.barOpen, self.barClose, self.barLow, self.barHigh, self.barOpenInterest
                self.onBar(self.num, self.barOpen, self.barClose, self.barLow, self.barHigh, self.barOpenInterest)
                self.num += 1

    # 画历史数据K线图
    def plotHistorticData(self):
        self.initCompleted = True
        for i in xrange(len(self.data)):
            self.onBar(i, self.data.index[i], self.data.open[i], self.data.close[i], self.data.low[i], self.data.high[i])
        self.plotKline()
        print "plotKLine success"

    #----------------------------------------------------------------------
    def initHistoricalData(self):
        """初始历史数据"""
        if self.symbol!='':
            print "download histrical data:",self.symbol
            self.initCompleted = True  # 读取历史数据完成
            td = timedelta(days=1)     # 读取3天的历史TICK数据

            # if startDate:
            #     cx = self.loadTick(self.symbol, startDate-td)
            # else:
            #     today = datetime.today().replace(hour=0, minute=0, second=0, microsecond=0)
            #     cx = self.loadTick(self.symbol, today-td)

            print cx.count()

            if cx:
                for data in cx:
                    tick = Tick(data['symbol'])

                    tick.openPrice = data['lastPrice']
                    tick.highPrice = data['upperLimit']
                    tick.lowPrice = data['lowerLimit']
                    tick.lastPrice = data['lastPrice']

                    tick.volume = data['volume']
                    tick.openInterest = data['openInterest']

                    tick.upperLimit = data['upperLimit']
                    tick.lowerLimit = data['lowerLimit']

                    tick.time = data['time']
                    # tick.ms = data['UpdateMillisec']

                    tick.bidPrice1 = data['bidPrice1']
                    tick.bidPrice2 = data['bidPrice2']
                    tick.bidPrice3 = data['bidPrice3']
                    tick.bidPrice4 = data['bidPrice4']
                    tick.bidPrice5 = data['bidPrice5']

                    tick.askPrice1 = data['askPrice1']
                    tick.askPrice2 = data['askPrice2']
                    tick.askPrice3 = data['askPrice3']
                    tick.askPrice4 = data['askPrice4']
                    tick.askPrice5 = data['askPrice5']

                    tick.bidVolume1 = data['bidVolume1']
                    tick.bidVolume2 = data['bidVolume2']
                    tick.bidVolume3 = data['bidVolume3']
                    tick.bidVolume4 = data['bidVolume4']
                    tick.bidVolume5 = data['bidVolume5']

                    tick.askVolume1 = data['askVolume1']
                    tick.askVolume2 = data['askVolume2']
                    tick.askVolume3 = data['askVolume3']
                    tick.askVolume4 = data['askVolume4']
                    tick.askVolume5 = data['askVolume5']

                    self.onTick(tick)

            print('load historic data completed')

    #----------------------------------------------------------------------
    def plotKline(self):
        """K线图"""
        if self.initCompleted:
            # 均线
            self.curve5.setData(self.listfastEMA, pen=(255, 0, 0), name="Red curve")
            self.curve6.setData(self.listslowEMA, pen=(0, 255, 0), name="Green curve")

            # 画K线
            self.pw2.removeItem(self.candle)
            self.candle = self.CandlestickItem(self.listBar)
            self.pw2.addItem(self.candle)

    #----------------------------------------------------------------------
    def plotText(self):
        lenClose = len(self.listClose)

        if lenClose >= 5:                                       # Fractal Signal
            if self.listClose[-1] > self.listClose[-2] and self.listClose[-3] > self.listClose[-2] and self.listClose[-4] > self.listClose[-2] and self.listClose[-5] > self.listClose[-2] and self.listfastEMA[-1] > self.listslowEMA[-1]:
                ## Draw an arrowhead next to the text box
                # self.pw2.removeItem(self.arrow)
                self.arrow = pg.ArrowItem(pos=(lenClose-1, self.listLow[-1]), angle=90, brush=(255, 0, 0))#红色
                self.pw2.addItem(self.arrow)
            elif self.listClose[-1] < self.listClose[-2] and self.listClose[-3] < self.listClose[-2] and self.listClose[-4] < self.listClose[-2] and self.listClose[-5] < self.listClose[-2] and self.listfastEMA[-1] < self.listslowEMA[-1]:
                ## Draw an arrowhead next to the text box
                # self.pw2.removeItem(self.arrow)
                self.arrow = pg.ArrowItem(pos=(lenClose-1, self.listHigh[-1]), angle=-90, brush=(0, 255, 0))#绿色
                self.pw2.addItem(self.arrow)

    #----------------------------------------------------------------------
    def onBar(self, n, t, o, c, l, h):
        self.listBar.append((n, t, o, c, l, h))
        self.listOpen.append(o)
        self.listClose.append(c)
        self.listHigh.append(h)
        self.listLow.append(l)

        #计算K线图EMA均线
        if self.fastEMA:
            self.fastEMA = c*self.EMAFastAlpha + self.fastEMA*(1-self.EMAFastAlpha)
            self.slowEMA = c*self.EMASlowAlpha + self.slowEMA*(1-self.EMASlowAlpha)
        else:
            self.fastEMA = c
            self.slowEMA = c
        self.listfastEMA.append(self.fastEMA)
        self.listslowEMA.append(self.slowEMA)

        self.plotText()    #显示开仓位置

    # ----------------------------------------------------------------------
    #画合并后的K线Bar
    def onBarAfterFenXing(self, n, t, o, c, l, h):
        self.listBar.append((n, t, o, c, l, h))

    def plotKlineAfterFenXing(self):
        # 画K线
        self.pw2.removeItem(self.candle)
        self.candle = self.CandlestickItem(self.listBar)
        self.pw2.addItem(self.candle)

    #----------------------------------------------------------------------
    def __connectMongo(self):
        """连接MongoDB数据库"""
        try:
            self.__mongoConnection = pymongo.MongoClient("localhost", 27017)
            self.__mongoConnected = True
            self.__mongoMinDB = self.__mongoConnection['VnTrader_1Min_Db']
        except ConnectionFailure:
            pass

########################################################################
class TickWidget(QtGui.QWidget):
    """用于显示价格走势图"""
    signal = QtCore.pyqtSignal(type(Event()))

    # tick图的相关参数、变量
    listlastPrice = np.empty(1000)

    fastMA = 0
    midMA = 0
    slowMA = 0
    listfastMA = np.empty(1000)
    listmidMA = np.empty(1000)
    listslowMA = np.empty(1000)
    tickFastAlpha = 0.0333    # 快速均线的参数,30
    tickMidAlpha = 0.0167     # 中速均线的参数,60
    tickSlowAlpha = 0.0083    # 慢速均线的参数,120

    ptr = 0
    ticktime = None  # tick数据时间

    class CandlestickItem(pg.GraphicsObject):
        def __init__(self, data):
            pg.GraphicsObject.__init__(self)
            self.data = data  ## data must have fields: time, open, close, min, max
            self.generatePicture()

        def generatePicture(self):
            ## pre-computing a QPicture object allows paint() to run much more quickly,
            ## rather than re-drawing the shapes every time.
            self.picture = QtGui.QPicture()
            p = QtGui.QPainter(self.picture)
            p.setPen(pg.mkPen(color='w', width=0.4))  # 0.4 means w*2
            a = pg.AxisItem('bottom', pen=None, linkView=None, parent=None, maxTickLength=-5, showValues=True)
            a.setFixedWidth(1)
            a.setWidth(1)
            a.setLabel(show=True)
            a.setGrid(grid=True)
            labelStyle = {'color': '#FFF', 'font-size': '14pt'}
            a.setLabel('label text', units='V', **labelStyle)
            # w = (self.data[1][0] - self.data[0][0]) / 3.
            w = 0.2
            for (t, open, close, min, max) in self.data:
                p.drawLine(QtCore.QPointF(t, min), QtCore.QPointF(t, max))
                if open > close:
                    p.setBrush(pg.mkBrush('g'))
                else:
                    p.setBrush(pg.mkBrush('r'))
                p.drawRect(QtCore.QRectF(t-w, open, w*2, close-open))
                pg.setConfigOption('leftButtonPan', False)
            p.end()

        def paint(self, p, *args):
            p.drawPicture(0, 0, self.picture)

        def boundingRect(self):
            ## boundingRect _must_ indicate the entire area that will be drawn on
            ## or else we will get artifacts and possibly crashing.
            ## (in this case, QPicture does all the work of computing the bouning rect for us)
            return QtCore.QRectF(self.picture.boundingRect())

    #----------------------------------------------------------------------
    def __init__(self, eventEngine, chanlunEngine, parent=None):
        """Constructor"""
        super(TickWidget, self).__init__(parent)

        self.__eventEngine = eventEngine
        self.__chanlunEngine = chanlunEngine
        # MongoDB数据库相关
        self.__mongoConnected = False
        self.__mongoConnection = None
        self.__mongoTickDB = None

        # 调用函数
        self.initUi()
        self.registerEvent()

    #----------------------------------------------------------------------
    def initUi(self):
        """初始化界面"""
        self.setWindowTitle(u'Tick')

        self.vbl_1 = QtGui.QHBoxLayout()
        self.initplotTick()  # plotTick初始化

        self.setLayout(self.vbl_1)

    #----------------------------------------------------------------------
    def initplotTick(self):
        """"""
        self.pw1 = pg.PlotWidget(name='Plot1')
        self.vbl_1.addWidget(self.pw1)
        self.pw1.setMinimumWidth(1500)
        self.pw1.setMaximumWidth(1800)
        self.pw1.setRange(xRange=[-360, 0])
        self.pw1.setLimits(xMax=5)
        self.pw1.setDownsampling(mode='peak')
        self.pw1.setClipToView(True)

        self.curve1 = self.pw1.plot()
        self.curve2 = self.pw1.plot()
        self.curve3 = self.pw1.plot()
        self.curve4 = self.pw1.plot()

    # #----------------------------------------------------------------------
    # def initHistoricalData(self,startDate=None):
    #     """初始历史数据"""
    #     print "download histrical data"
    #     self.initCompleted = True  # 读取历史数据完成
    #     td = timedelta(days=1)     # 读取3天的历史TICK数据
    #
    #     if startDate:
    #         cx = self.loadTick(self.symbol, startDate-td)
    #     else:
    #         today = datetime.today().replace(hour=0, minute=0, second=0, microsecond=0)
    #         cx = self.loadTick(self.symbol, today-td)
    #
    #     print cx.count()
    #
    #     if cx:
    #         for data in cx:
    #             tick = Tick(data['symbol'])
    #
    #             tick.openPrice = data['lastPrice']
    #             tick.highPrice = data['upperLimit']
    #             tick.lowPrice = data['lowerLimit']
    #             tick.lastPrice = data['lastPrice']
    #
    #             tick.volume = data['volume']
    #             tick.openInterest = data['openInterest']
    #
    #             tick.upperLimit = data['upperLimit']
    #             tick.lowerLimit = data['lowerLimit']
    #
    #             tick.time = data['time']
    #             # tick.ms = data['UpdateMillisec']
    #
    #             tick.bidPrice1 = data['bidPrice1']
    #             tick.bidPrice2 = data['bidPrice2']
    #             tick.bidPrice3 = data['bidPrice3']
    #             tick.bidPrice4 = data['bidPrice4']
    #             tick.bidPrice5 = data['bidPrice5']
    #
    #             tick.askPrice1 = data['askPrice1']
    #             tick.askPrice2 = data['askPrice2']
    #             tick.askPrice3 = data['askPrice3']
    #             tick.askPrice4 = data['askPrice4']
    #             tick.askPrice5 = data['askPrice5']
    #
    #             tick.bidVolume1 = data['bidVolume1']
    #             tick.bidVolume2 = data['bidVolume2']
    #             tick.bidVolume3 = data['bidVolume3']
    #             tick.bidVolume4 = data['bidVolume4']
    #             tick.bidVolume5 = data['bidVolume5']
    #
    #             tick.askVolume1 = data['askVolume1']
    #             tick.askVolume2 = data['askVolume2']
    #             tick.askVolume3 = data['askVolume3']
    #             tick.askVolume4 = data['askVolume4']
    #             tick.askVolume5 = data['askVolume5']
    #
    #             self.onTick(tick)
    #
    #     print('load historic data completed')

    #----------------------------------------------------------------------
    def plotTick(self):
        """画tick图"""
        self.curve1.setData(self.listlastPrice[:self.ptr])
        self.curve2.setData(self.listfastMA[:self.ptr], pen=(255, 0, 0), name="Red curve")
        self.curve3.setData(self.listmidMA[:self.ptr], pen=(0, 255, 0), name="Green curve")
        self.curve4.setData(self.listslowMA[:self.ptr], pen=(0, 0, 255), name="Blue curve")
        self.curve1.setPos(-self.ptr, 0)
        self.curve2.setPos(-self.ptr, 0)
        self.curve3.setPos(-self.ptr, 0)
        self.curve4.setPos(-self.ptr, 0)

    #----------------------------------------------------------------------
    def updateMarketData(self, event):
        """更新行情"""
        data = event.dict_['data']
        print "update", data['InstrumentID']
        symbol = data['InstrumentID']
        tick = Tick(symbol)
        tick.openPrice = data['OpenPrice']
        tick.highPrice = data['HighestPrice']
        tick.lowPrice = data['LowestPrice']
        tick.lastPrice = data['LastPrice']

        tick.volume = data['Volume']
        tick.openInterest = data['OpenInterest']

        tick.upperLimit = data['UpperLimitPrice']
        tick.lowerLimit = data['LowerLimitPrice']

        tick.time = data['UpdateTime']
        tick.ms = data['UpdateMillisec']

        tick.bidPrice1 = data['BidPrice1']
        tick.bidPrice2 = data['BidPrice2']
        tick.bidPrice3 = data['BidPrice3']
        tick.bidPrice4 = data['BidPrice4']
        tick.bidPrice5 = data['BidPrice5']

        tick.askPrice1 = data['AskPrice1']
        tick.askPrice2 = data['AskPrice2']
        tick.askPrice3 = data['AskPrice3']
        tick.askPrice4 = data['AskPrice4']
        tick.askPrice5 = data['AskPrice5']

        tick.bidVolume1 = data['BidVolume1']
        tick.bidVolume2 = data['BidVolume2']
        tick.bidVolume3 = data['BidVolume3']
        tick.bidVolume4 = data['BidVolume4']
        tick.bidVolume5 = data['BidVolume5']

        tick.askVolume1 = data['AskVolume1']
        tick.askVolume2 = data['AskVolume2']
        tick.askVolume3 = data['AskVolume3']
        tick.askVolume4 = data['AskVolume4']
        tick.askVolume5 = data['AskVolume5']

        self.onTick(tick)  # tick数据更新
        self.__recordTick(tick)  #记录Tick数据

    #----------------------------------------------------------------------
    def onTick(self, tick):
        """tick数据更新"""
        from datetime import time

        # 首先生成datetime.time格式的时间（便于比较）,从字符串时间转化为time格式的时间
        hh, mm, ss = tick.time.split(':')
        self.ticktime = time(int(hh), int(mm), int(ss), microsecond=tick.ms)

        # 计算tick图的相关参数
        if self.ptr == 0:
            self.fastMA = tick.lastPrice
            self.midMA = tick.lastPrice
            self.slowMA = tick.lastPrice
        else:
            self.fastMA = (1-self.tickFastAlpha) * self.fastMA + self.tickFastAlpha * tick.lastPrice
            self.midMA = (1-self.tickMidAlpha) * self.midMA + self.tickMidAlpha * tick.lastPrice
            self.slowMA = (1-self.tickSlowAlpha) * self.slowMA + self.tickSlowAlpha * tick.lastPrice
        self.listlastPrice[self.ptr] = int(tick.lastPrice)
        self.listfastMA[self.ptr] = int(self.fastMA)
        self.listmidMA[self.ptr] = int(self.midMA)
        self.listslowMA[self.ptr] = int(self.slowMA)

        self.ptr += 1
        print(self.ptr)
        if self.ptr >= self.listlastPrice.shape[0]:
            tmp = self.listlastPrice
            self.listlastPrice = np.empty(self.listlastPrice.shape[0] * 2)
            self.listlastPrice[:tmp.shape[0]] = tmp

            tmp = self.listfastMA
            self.listfastMA = np.empty(self.listfastMA.shape[0] * 2)
            self.listfastMA[:tmp.shape[0]] = tmp

            tmp = self.listmidMA
            self.listmidMA = np.empty(self.listmidMA.shape[0] * 2)
            self.listmidMA[:tmp.shape[0]] = tmp

            tmp = self.listslowMA
            self.listslowMA = np.empty(self.listslowMA.shape[0] * 2)
            self.listslowMA[:tmp.shape[0]] = tmp

         # 调用画图函数
        self.plotTick()  # tick图

    #----------------------------------------------------------------------
    def __connectMongo(self):
        """连接MongoDB数据库"""
        try:
            self.__mongoConnection = pymongo.MongoClient("localhost", 27017)
            self.__mongoConnected = True
            self.__mongoTickDB = self.__mongoConnection['VnTrader_Tick_Db']
        except ConnectionFailure:
            pass

    #----------------------------------------------------------------------
    def __recordTick(self, data):
        """将Tick数据插入到MongoDB中"""
        if self.__mongoConnected:
            symbol = data['InstrumentID']
            data['date'] = datetime.now().strftime('%Y%m%d')
            self.__mongoTickDB[symbol].insert(data)

    # #----------------------------------------------------------------------
    # def loadTick(self, symbol, startDate, endDate=None):
    #     """从MongoDB中读取Tick数据"""
    #     cx = self.__mongoTickDB[symbol].find()
    #     print cx.count()
    #     return cx
    #     # if self.__mongoConnected:
    #     #     collection = self.__mongoTickDB[symbol]
    #     #
    #     #     # 如果输入了读取TICK的最后日期
    #     #     if endDate:
    #     #         cx = collection.find({'date': {'$gte': startDate, '$lte': endDate}})
    #     #     else:
    #     #         cx = collection.find({'date': {'$gte': startDate}})
    #     #     return cx
    #     # else:
    #     #     return None

    #----------------------------------------------------------------------
    def registerEvent(self):
        """注册事件监听"""
        print "connect"
        self.signal.connect(self.updateMarketData)
        self.__eventEngine.register(EVENT_MARKETDATA, self.signal.emit)

class Tick:
    """Tick数据对象"""

    #----------------------------------------------------------------------
    def __init__(self, symbol):
        """Constructor"""
        self.symbol = symbol        # 合约代码

        self.openPrice = 0          # OHLC
        self.highPrice = 0
        self.lowPrice = 0
        self.lastPrice = 0

        self.volume = 0             # 成交量
        self.openInterest = 0       # 持仓量

        self.upperLimit = 0         # 涨停价
        self.lowerLimit = 0         # 跌停价

        self.time = ''              # 更新时间和毫秒
        self.ms = 0

        self.bidPrice1 = 0          # 深度行情
        self.bidPrice2 = 0
        self.bidPrice3 = 0
        self.bidPrice4 = 0
        self.bidPrice5 = 0

        self.askPrice1 = 0
        self.askPrice2 = 0
        self.askPrice3 = 0
        self.askPrice4 = 0
        self.askPrice5 = 0

        self.bidVolume1 = 0
        self.bidVolume2 = 0
        self.bidVolume3 = 0
        self.bidVolume4 = 0
        self.bidVolume5 = 0

        self.askVolume1 = 0
        self.askVolume2 = 0
        self.askVolume3 = 0
        self.askVolume4 = 0
        self.askVolume5 = 0