Qwt User's Guide  6.2.0
qwt_plot_tradingcurve.cpp
1 /******************************************************************************
2  * Qwt Widget Library
3  * Copyright (C) 1997 Josef Wilgen
4  * Copyright (C) 2002 Uwe Rathmann
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the Qwt License, Version 1.0
8  *****************************************************************************/
9 
10 #include "qwt_plot_tradingcurve.h"
11 #include "qwt_scale_map.h"
12 #include "qwt_painter.h"
13 #include "qwt_text.h"
14 #include "qwt_graphic.h"
15 #include "qwt_math.h"
16 
17 #include <qpainter.h>
18 
19 static inline bool qwtIsSampleInside( const QwtOHLCSample& sample,
20  double tMin, double tMax, double vMin, double vMax )
21 {
22  const double t = sample.time;
23  const QwtInterval interval = sample.boundingInterval();
24 
25  const bool isOffScreen = ( t < tMin ) || ( t > tMax )
26  || ( interval.maxValue() < vMin ) || ( interval.minValue() > vMax );
27 
28  return !isOffScreen;
29 }
30 
31 class QwtPlotTradingCurve::PrivateData
32 {
33  public:
34  PrivateData()
36  , symbolExtent( 0.6 )
37  , minSymbolWidth( 2.0 )
38  , maxSymbolWidth( -1.0 )
39  , paintAttributes( QwtPlotTradingCurve::ClipSymbols )
40  {
41  symbolBrush[0] = QBrush( Qt::white );
42  symbolBrush[1] = QBrush( Qt::black );
43  }
44 
46  double symbolExtent;
47  double minSymbolWidth;
48  double maxSymbolWidth;
49 
50  QPen symbolPen;
51  QBrush symbolBrush[2]; // Increasing/Decreasing
52 
54 };
55 
61  : QwtPlotSeriesItem( title )
62 {
63  init();
64 }
65 
71  : QwtPlotSeriesItem( QwtText( title ) )
72 {
73  init();
74 }
75 
78 {
79  delete m_data;
80 }
81 
84 {
87 
88  m_data = new PrivateData;
90 
91  setZ( 19.0 );
92 }
93 
96 {
98 }
99 
108  PaintAttribute attribute, bool on )
109 {
110  if ( on )
111  m_data->paintAttributes |= attribute;
112  else
113  m_data->paintAttributes &= ~attribute;
114 }
115 
121  PaintAttribute attribute ) const
122 {
123  return ( m_data->paintAttributes & attribute );
124 }
125 
133  const QVector< QwtOHLCSample >& samples )
134 {
135  setData( new QwtTradingChartData( samples ) );
136 }
137 
150 {
151  setData( data );
152 }
153 
163 {
164  if ( style != m_data->symbolStyle )
165  {
166  m_data->symbolStyle = style;
167 
168  legendChanged();
169  itemChanged();
170  }
171 }
172 
178 {
179  return m_data->symbolStyle;
180 }
181 
196  const QColor& color, qreal width, Qt::PenStyle style )
197 {
198  setSymbolPen( QPen( color, width, style ) );
199 }
200 
209 void QwtPlotTradingCurve::setSymbolPen( const QPen& pen )
210 {
211  if ( pen != m_data->symbolPen )
212  {
213  m_data->symbolPen = pen;
214 
215  legendChanged();
216  itemChanged();
217  }
218 }
219 
225 {
226  return m_data->symbolPen;
227 }
228 
239  Direction direction, const QBrush& brush )
240 {
241  // silencing -Wtautological-constant-out-of-range-compare
242  const int index = static_cast< int >( direction );
243  if ( index < 0 || index >= 2 )
244  return;
245 
246  if ( brush != m_data->symbolBrush[ index ] )
247  {
248  m_data->symbolBrush[ index ] = brush;
249 
250  legendChanged();
251  itemChanged();
252  }
253 }
254 
263 {
264  const int index = static_cast< int >( direction );
265  if ( index < 0 || index >= 2 )
266  return QBrush();
267 
268  return m_data->symbolBrush[ index ];
269 }
270 
285 {
286  extent = qwtMaxF( 0.0, extent );
287  if ( extent != m_data->symbolExtent )
288  {
289  m_data->symbolExtent = extent;
290 
291  legendChanged();
292  itemChanged();
293  }
294 }
295 
302 {
303  return m_data->symbolExtent;
304 }
305 
313 {
314  width = qwtMaxF( width, 0.0 );
315  if ( width != m_data->minSymbolWidth )
316  {
317  m_data->minSymbolWidth = width;
318 
319  legendChanged();
320  itemChanged();
321  }
322 }
323 
329 {
330  return m_data->minSymbolWidth;
331 }
332 
342 {
343  if ( width != m_data->maxSymbolWidth )
344  {
345  m_data->maxSymbolWidth = width;
346 
347  legendChanged();
348  itemChanged();
349  }
350 }
351 
357 {
358  return m_data->maxSymbolWidth;
359 }
360 
366 {
367  QRectF rect = QwtPlotSeriesItem::boundingRect();
368  if ( orientation() == Qt::Vertical )
369  rect.setRect( rect.y(), rect.x(), rect.height(), rect.width() );
370 
371  return rect;
372 }
373 
387 void QwtPlotTradingCurve::drawSeries( QPainter* painter,
388  const QwtScaleMap& xMap, const QwtScaleMap& yMap,
389  const QRectF& canvasRect, int from, int to ) const
390 {
391  if ( to < 0 )
392  to = dataSize() - 1;
393 
394  if ( from < 0 )
395  from = 0;
396 
397  if ( from > to )
398  return;
399 
400  painter->save();
401 
402  if ( m_data->symbolStyle != QwtPlotTradingCurve::NoSymbol )
403  drawSymbols( painter, xMap, yMap, canvasRect, from, to );
404 
405  painter->restore();
406 }
407 
420 void QwtPlotTradingCurve::drawSymbols( QPainter* painter,
421  const QwtScaleMap& xMap, const QwtScaleMap& yMap,
422  const QRectF& canvasRect, int from, int to ) const
423 {
424  const QRectF tr = QwtScaleMap::invTransform( xMap, yMap, canvasRect );
425 
426  const QwtScaleMap* timeMap, * valueMap;
427  double tMin, tMax, vMin, vMax;
428 
429  const Qt::Orientation orient = orientation();
430  if ( orient == Qt::Vertical )
431  {
432  timeMap = &xMap;
433  valueMap = &yMap;
434 
435  tMin = tr.left();
436  tMax = tr.right();
437  vMin = tr.top();
438  vMax = tr.bottom();
439  }
440  else
441  {
442  timeMap = &yMap;
443  valueMap = &xMap;
444 
445  vMin = tr.left();
446  vMax = tr.right();
447  tMin = tr.top();
448  tMax = tr.bottom();
449  }
450 
451  const bool inverted = timeMap->isInverting();
452  const bool doClip = m_data->paintAttributes & ClipSymbols;
453  const bool doAlign = QwtPainter::roundingAlignment( painter );
454 
455  double symbolWidth = scaledSymbolWidth( xMap, yMap, canvasRect );
456  if ( doAlign )
457  symbolWidth = std::floor( 0.5 * symbolWidth ) * 2.0;
458 
459  QPen pen = m_data->symbolPen;
460  pen.setCapStyle( Qt::FlatCap );
461 
462  painter->setPen( pen );
463 
464  for ( int i = from; i <= to; i++ )
465  {
466  const QwtOHLCSample s = sample( i );
467 
468  if ( !doClip || qwtIsSampleInside( s, tMin, tMax, vMin, vMax ) )
469  {
470  QwtOHLCSample translatedSample;
471 
472  translatedSample.time = timeMap->transform( s.time );
473  translatedSample.open = valueMap->transform( s.open );
474  translatedSample.high = valueMap->transform( s.high );
475  translatedSample.low = valueMap->transform( s.low );
476  translatedSample.close = valueMap->transform( s.close );
477 
478  const int brushIndex = ( s.open < s.close )
481 
482  if ( doAlign )
483  {
484  translatedSample.time = qRound( translatedSample.time );
485  translatedSample.open = qRound( translatedSample.open );
486  translatedSample.high = qRound( translatedSample.high );
487  translatedSample.low = qRound( translatedSample.low );
488  translatedSample.close = qRound( translatedSample.close );
489  }
490 
491  switch( m_data->symbolStyle )
492  {
493  case Bar:
494  {
495  drawBar( painter, translatedSample,
496  orient, inverted, symbolWidth );
497  break;
498  }
499  case CandleStick:
500  {
501  painter->setBrush( m_data->symbolBrush[ brushIndex ] );
502  drawCandleStick( painter, translatedSample,
503  orient, symbolWidth );
504  break;
505  }
506  default:
507  {
508  if ( m_data->symbolStyle >= UserSymbol )
509  {
510  painter->setBrush( m_data->symbolBrush[ brushIndex ] );
511  drawUserSymbol( painter, m_data->symbolStyle,
512  translatedSample, orient, inverted, symbolWidth );
513  }
514  }
515  }
516  }
517  }
518 }
519 
534 void QwtPlotTradingCurve::drawUserSymbol( QPainter* painter,
535  SymbolStyle symbolStyle, const QwtOHLCSample& sample,
536  Qt::Orientation orientation, bool inverted, double symbolWidth ) const
537 {
538  Q_UNUSED( painter )
539  Q_UNUSED( symbolStyle )
540  Q_UNUSED( orientation )
541  Q_UNUSED( inverted )
542  Q_UNUSED( symbolWidth )
543  Q_UNUSED( sample )
544 }
545 
562 void QwtPlotTradingCurve::drawBar( QPainter* painter,
563  const QwtOHLCSample& sample, Qt::Orientation orientation,
564  bool inverted, double width ) const
565 {
566  double w2 = 0.5 * width;
567  if ( inverted )
568  w2 *= -1;
569 
570  if ( orientation == Qt::Vertical )
571  {
572  QwtPainter::drawLine( painter,
574 
575  QwtPainter::drawLine( painter,
577  QwtPainter::drawLine( painter,
579  }
580  else
581  {
583  sample.high, sample.time );
584  QwtPainter::drawLine( painter,
586  QwtPainter::drawLine( painter,
588  }
589 }
590 
601 void QwtPlotTradingCurve::drawCandleStick( QPainter* painter,
602  const QwtOHLCSample& sample, Qt::Orientation orientation,
603  double width ) const
604 {
605  const double t = sample.time;
606  const double v1 = qwtMinF( sample.low, sample.high );
607  const double v2 = qwtMinF( sample.open, sample.close );
608  const double v3 = qwtMaxF( sample.low, sample.high );
609  const double v4 = qwtMaxF( sample.open, sample.close );
610 
611  if ( orientation == Qt::Vertical )
612  {
613  QwtPainter::drawLine( painter, t, v1, t, v2 );
614  QwtPainter::drawLine( painter, t, v3, t, v4 );
615 
616  QRectF rect( t - 0.5 * width, sample.open,
617  width, sample.close - sample.open );
618 
619  QwtPainter::drawRect( painter, rect );
620  }
621  else
622  {
623  QwtPainter::drawLine( painter, v1, t, v2, t );
624  QwtPainter::drawLine( painter, v3, t, v4, t );
625 
626  const QRectF rect( sample.open, t - 0.5 * width,
627  sample.close - sample.open, width );
628 
629  QwtPainter::drawRect( painter, rect );
630  }
631 }
632 
643  const QSizeF& size ) const
644 {
645  Q_UNUSED( index );
646  return defaultIcon( m_data->symbolPen.color(), size );
647 }
648 
665  const QwtScaleMap& xMap, const QwtScaleMap& yMap,
666  const QRectF& canvasRect ) const
667 {
668  Q_UNUSED( canvasRect );
669 
670  if ( m_data->maxSymbolWidth > 0.0 &&
671  m_data->minSymbolWidth >= m_data->maxSymbolWidth )
672  {
673  return m_data->minSymbolWidth;
674  }
675 
676  const QwtScaleMap* map =
677  ( orientation() == Qt::Vertical ) ? &xMap : &yMap;
678 
679  const double pos = map->transform( map->s1() + m_data->symbolExtent );
680 
681  double width = qAbs( pos - map->p1() );
682 
683  width = qwtMaxF( width, m_data->minSymbolWidth );
684  if ( m_data->maxSymbolWidth > 0.0 )
685  width = qwtMinF( width, m_data->maxSymbolWidth );
686 
687  return width;
688 }
A paint device for scalable graphics.
Definition: qwt_graphic.h:76
A class representing an interval.
Definition: qwt_interval.h:23
double minValue() const
Definition: qwt_interval.h:192
double maxValue() const
Definition: qwt_interval.h:198
Open-High-Low-Close sample used in financial charts.
Definition: qwt_samples.h:144
double high
Highest price.
Definition: qwt_samples.h:164
double open
Opening price.
Definition: qwt_samples.h:161
double close
Closing price.
Definition: qwt_samples.h:170
QwtInterval boundingInterval() const
Calculate the bounding interval of the OHLC values.
Definition: qwt_samples.h:220
double low
Lowest price.
Definition: qwt_samples.h:167
static void drawRect(QPainter *, qreal x, qreal y, qreal w, qreal h)
Wrapper for QPainter::drawRect()
static bool roundingAlignment()
Definition: qwt_painter.h:183
static void drawLine(QPainter *, qreal x1, qreal y1, qreal x2, qreal y2)
Wrapper for QPainter::drawLine()
Definition: qwt_painter.h:154
virtual void legendChanged()
void setZ(double z)
Set the z value.
void setItemAttribute(ItemAttribute, bool on=true)
QwtGraphic defaultIcon(const QBrush &, const QSizeF &) const
Return a default icon from a brush.
@ Rtti_PlotTradingCurve
For QwtPlotTradingCurve.
virtual void itemChanged()
@ Legend
The item is represented on the legend.
Base class for plot items representing a series of samples.
Qt::Orientation orientation() const
virtual QRectF boundingRect() const override
QwtPlotTradingCurve illustrates movements in the price of a financial instrument over time.
void setSymbolStyle(SymbolStyle style)
QBrush symbolBrush(Direction) const
bool testPaintAttribute(PaintAttribute) const
void drawBar(QPainter *, const QwtOHLCSample &, Qt::Orientation, bool inverted, double width) const
Draw a bar.
SymbolStyle symbolStyle() const
void drawCandleStick(QPainter *, const QwtOHLCSample &, Qt::Orientation, double width) const
Draw a candle stick.
QFlags< PaintAttribute > PaintAttributes
virtual void drawUserSymbol(QPainter *, SymbolStyle, const QwtOHLCSample &, Qt::Orientation, bool inverted, double symbolWidth) const
Draw a symbol for a symbol style >= UserSymbol.
void setSamples(const QVector< QwtOHLCSample > &)
virtual QwtGraphic legendIcon(int index, const QSizeF &) const override
virtual QRectF boundingRect() const override
virtual void drawSymbols(QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to) const
virtual void drawSeries(QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to) const override
virtual ~QwtPlotTradingCurve()
Destructor.
void init()
Initialize internal members.
void setSymbolPen(const QColor &, qreal width=0.0, Qt::PenStyle=Qt::SolidLine)
void setSymbolExtent(double)
Set the extent of the symbol.
Direction
Direction of a price movement.
@ Increasing
The closing price is higher than the opening price.
@ Decreasing
The closing price is lower than the opening price.
void setPaintAttribute(PaintAttribute, bool on=true)
virtual double scaledSymbolWidth(const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect) const
void setSymbolBrush(Direction, const QBrush &)
@ NoSymbol
Nothing is displayed.
virtual int rtti() const override
QwtPlotTradingCurve(const QString &title=QString())
@ ClipSymbols
Check if a symbol is on the plot canvas before painting it.
A scale map.
Definition: qwt_scale_map.h:27
bool isInverting() const
double p1() const
Definition: qwt_scale_map.h:99
double transform(double s) const
double s1() const
Definition: qwt_scale_map.h:83
double invTransform(double p) const
Abstract interface for iterating over samples.
QwtOHLCSample sample(int index) const
virtual size_t dataSize() const override
QwtSeriesData< QwtOHLCSample > * data()
void setData(QwtSeriesData< QwtOHLCSample > *series)
A class representing a text.
Definition: qwt_text.h:52