├── WX@2x.png
├── Resource
├── 横屏.png
├── 火币.jpg
├── 竖屏.png
├── kline.gif
├── 内存消耗.png
└── 宏定义适配.png
├── .gitattributes
├── Podfile
├── AbuKlineView.xcworkspace
├── xcuserdata
│ ├── jefferson.zhang.xcuserdatad
│ │ ├── xcdebugger
│ │ │ └── Breakpoints_v2.xcbkptlist
│ │ └── UserInterfaceState.xcuserstate
│ ├── haoji.xcuserdatad
│ │ ├── UserInterfaceState.xcuserstate
│ │ └── xcdebugger
│ │ │ └── Breakpoints_v2.xcbkptlist
│ └── jefferson.xcuserdatad
│ │ ├── UserInterfaceState.xcuserstate
│ │ └── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
├── contents.xcworkspacedata
└── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── .gitignore
├── AbuKlineView.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── haoji.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
└── xcuserdata
│ ├── imac.xcuserdatad
│ └── xcschemes
│ │ └── xcschememanagement.plist
│ ├── haoji.xcuserdatad
│ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── AbuKlineView.xcscheme
│ ├── jefferson.xcuserdatad
│ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── AbuKlineView.xcscheme
│ └── jefferson.zhang.xcuserdatad
│ └── xcschemes
│ ├── xcschememanagement.plist
│ └── AbuKlineView.xcscheme
├── AbuKlineView
├── ViewController.h
├── BaseViewController.h
├── KlineView
│ ├── Category
│ │ ├── UIColor+Extension.h
│ │ ├── UIBezierPath+Extension.h
│ │ ├── UIView+Extension.h
│ │ ├── UIColor+Extension.m
│ │ ├── UIView+Extension.m
│ │ └── UIBezierPath+Extension.m
│ ├── KLineView
│ │ ├── KLineView
│ │ │ ├── AbuKlineView.h
│ │ │ ├── AbuCharViewProtocol.h
│ │ │ ├── AbuCandChartView.h
│ │ │ ├── AbuKlineView.m
│ │ │ └── AbuCandChartView.m
│ │ ├── KlineCommonView
│ │ │ ├── KlineVerticalView.h
│ │ │ ├── KlineCurrentPriceView.h
│ │ │ ├── KlinePriceView.h
│ │ │ ├── KlineCurrentPriceView.m
│ │ │ ├── KlineVerticalView.m
│ │ │ └── KlinePriceView.m
│ │ ├── KLineLayer
│ │ │ ├── KlineTimeLayer.h
│ │ │ ├── KlineQuotaColumnLayer.h
│ │ │ ├── KlineCandelLayer.h
│ │ │ ├── KlineMALayer.h
│ │ │ ├── KlineTimeLayer.m
│ │ │ ├── KlineCandelLayer.m
│ │ │ ├── KlineQuotaColumnLayer.m
│ │ │ └── KlineMALayer.m
│ │ ├── KLineCaculate
│ │ │ ├── KLineCalculate.h
│ │ │ ├── KLineSubCalculate.h
│ │ │ ├── KLineSubCalculate.m
│ │ │ └── KLineCalculate.m
│ │ └── KLineTitleView
│ │ │ ├── KlineTitleView.h
│ │ │ └── KlineTitleView.m
│ ├── KLineModel
│ │ ├── KLineModel.m
│ │ └── KLineModel.h
│ └── APIManage
│ │ └── PrefixHeader.pch
├── main.m
├── AppDelegate.h
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Info.plist
├── BaseViewController.m
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── AppDelegate.m
├── Prefix.pch
├── ViewController.m
├── stock30.json
└── stock5.json
├── Podfile.lock
└── README.md
/WX@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AbuIOSDeveloper/KLine/HEAD/WX@2x.png
--------------------------------------------------------------------------------
/Resource/横屏.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AbuIOSDeveloper/KLine/HEAD/Resource/横屏.png
--------------------------------------------------------------------------------
/Resource/火币.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AbuIOSDeveloper/KLine/HEAD/Resource/火币.jpg
--------------------------------------------------------------------------------
/Resource/竖屏.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AbuIOSDeveloper/KLine/HEAD/Resource/竖屏.png
--------------------------------------------------------------------------------
/Resource/kline.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AbuIOSDeveloper/KLine/HEAD/Resource/kline.gif
--------------------------------------------------------------------------------
/Resource/内存消耗.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AbuIOSDeveloper/KLine/HEAD/Resource/内存消耗.png
--------------------------------------------------------------------------------
/Resource/宏定义适配.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AbuIOSDeveloper/KLine/HEAD/Resource/宏定义适配.png
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 | *.c linguist-language=Objective-C
4 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios,'7.0'
2 | target 'AbuKlineView' do
3 |
4 | pod 'Masonry'
5 | pod 'KVOController'
6 | pod 'MJExtension'
7 |
8 | end
9 |
--------------------------------------------------------------------------------
/AbuKlineView.xcworkspace/xcuserdata/jefferson.zhang.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | AbuKlineView.xcworkspace/xcuserdata/jefferson.xcuserdatad/UserInterfaceState.xcuserstate
3 | *.xcuserstate
4 | AbuKlineView.xcworkspace/xcuserdata/jefferson.xcuserdatad/UserInterfaceState.xcuserstate
5 |
--------------------------------------------------------------------------------
/AbuKlineView.xcworkspace/xcuserdata/haoji.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AbuIOSDeveloper/KLine/HEAD/AbuKlineView.xcworkspace/xcuserdata/haoji.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/AbuKlineView.xcworkspace/xcuserdata/jefferson.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AbuIOSDeveloper/KLine/HEAD/AbuKlineView.xcworkspace/xcuserdata/jefferson.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/AbuKlineView.xcworkspace/xcuserdata/jefferson.zhang.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AbuIOSDeveloper/KLine/HEAD/AbuKlineView.xcworkspace/xcuserdata/jefferson.zhang.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/AbuKlineView.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/AbuKlineView.xcodeproj/project.xcworkspace/xcuserdata/haoji.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AbuIOSDeveloper/KLine/HEAD/AbuKlineView.xcodeproj/project.xcworkspace/xcuserdata/haoji.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/AbuKlineView/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // AbuKlineView
4 | //
5 | // Created by 阿布 on 17/9/6.
6 | // Copyright © 2017年 阿布. All rights reserved.
7 | //
8 |
9 | #import "BaseViewController.h"
10 |
11 | @interface ViewController : BaseViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/AbuKlineView.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/AbuKlineView.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/AbuKlineView/BaseViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // BaseViewController.h
3 | // AbuKline
4 | //
5 | // Created by jefferson on 2018/8/27.
6 | // Copyright © 2018年 jefferson. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface BaseViewController : UIViewController
12 |
13 | - (void)supportRotion:(int)rotion;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/Category/UIColor+Extension.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor+Extension.h
3 | // AbuKlineView
4 | //
5 | // Created by 阿布 on 17/9/6.
6 | // Copyright © 2017年 阿布. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UIColor (Extension)
12 |
13 | + (UIColor *)colorWithHexString:(NSString *)color;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/AbuKlineView/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // AbuKlineView
4 | //
5 | // Created by 阿布 on 17/9/6.
6 | // Copyright © 2017年 阿布. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/AbuKlineView/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // AbuKlineView
4 | //
5 | // Created by 阿布 on 17/9/6.
6 | // Copyright © 2017年 阿布. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 | @property (nonatomic,assign)BOOL allowRotation;
16 |
17 | @end
18 |
19 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KLineView/AbuKlineView.h:
--------------------------------------------------------------------------------
1 | //
2 | // AbuKlineView.h
3 | // AbuKlineView
4 | //
5 | // Created by Jefferson.zhang on 2017/9/6.
6 | // Copyright © 2017年 阿布. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 | @interface AbuKlineView : UIView
13 |
14 |
15 | @property (nonatomic,strong) NSMutableArray<__kindof KLineModel*> *dataArray;
16 |
17 | - (void)refreshFSKlineView:(KLineModel *)model;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/AbuKlineView.xcodeproj/xcuserdata/imac.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | AbuKlineView.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KlineCommonView/KlineVerticalView.h:
--------------------------------------------------------------------------------
1 | //
2 | // KlineVerticalView.h
3 | // ABuKLineChartView
4 | //
5 | // Created by jefferson on 2018/9/14.
6 | // Copyright © 2018年 jefferson. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface KlineVerticalView : UIView
12 | - (void)updateTimeString:(NSString *)timeString;
13 | - (void)updateTimeLeft:(CGFloat)leftdistance;
14 | - (void)updateHeight:(CGFloat)candleChartHeight;
15 | @end
16 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KlineCommonView/KlineCurrentPriceView.h:
--------------------------------------------------------------------------------
1 | //
2 | // KlineCurrentPriceView.h
3 | // ABuKLineChartView
4 | //
5 | // Created by jefferson on 2018/9/14.
6 | // Copyright © 2018年 jefferson. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface KlineCurrentPriceView : UIView
12 | - (instancetype)initWithUpdate:(BOOL)update;
13 | - (void)updateNewPrice:(NSString *)newPrice backgroundColor:(UIColor *)color precision:(int)precision;
14 | @end
15 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KLineLayer/KlineTimeLayer.h:
--------------------------------------------------------------------------------
1 | //
2 | // KlineTimeLayer.h
3 | // ABuKLineChartView
4 | //
5 | // Created by jefferson on 2018/9/7.
6 | // Copyright © 2018年 jefferson. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface KlineTimeLayer : CAShapeLayer
12 | - (instancetype)initQuotaDataArr:(NSArray *)dataArr candleWidth:(CGFloat)candleWidth height:(CGFloat)height timeHight:(CGFloat)timeHeight bottomMargin:(CGFloat)bottomMargin lineWidth:(CGFloat)lineWidth;
13 | @end
14 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KLineLayer/KlineQuotaColumnLayer.h:
--------------------------------------------------------------------------------
1 | //
2 | // KlineQuotaColumnLayer.h
3 | // ABuKLineChartView
4 | //
5 | // Created by jefferson on 2018/9/10.
6 | // Copyright © 2018年 jefferson. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface KlineQuotaColumnLayer : CAShapeLayer
12 | - (instancetype)initQuotaDataArr:(NSArray *)dataArr candleWidth:(CGFloat)candleWidth candleSpace:(CGFloat)candleSpace startIndex:(CGFloat)startIndex maxValue:(CGFloat)maxValue heightPerpoint:(CGFloat)heightPerpoint qutoaHeight:(CGFloat)qutoaHeight;
13 | @end
14 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KLineLayer/KlineCandelLayer.h:
--------------------------------------------------------------------------------
1 | //
2 | // KlineCandelLayer.h
3 | // ABuKLineChartView
4 | //
5 | // Created by jefferson on 2018/9/7.
6 | // Copyright © 2018年 jefferson. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface KlineCandelLayer : CAShapeLayer
12 |
13 | - (instancetype)initQuotaDataArr:(NSArray *)dataArr candleWidth:(CGFloat)candleWidth candleSpace:(CGFloat)candleSpace startIndex:(CGFloat)startIndex maxValue:(CGFloat)maxValue heightPerpoint:(CGFloat)heightPerpoint scrollViewContentWidth:(CGFloat)contentWidth;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - KVOController (1.2.0)
3 | - Masonry (1.0.2)
4 | - MJExtension (3.0.15.1)
5 |
6 | DEPENDENCIES:
7 | - KVOController
8 | - Masonry
9 | - MJExtension
10 |
11 | SPEC REPOS:
12 | https://github.com/cocoapods/specs.git:
13 | - KVOController
14 | - Masonry
15 | - MJExtension
16 |
17 | SPEC CHECKSUMS:
18 | KVOController: d72ace34afea42468329623b3379ab3cd1d286b6
19 | Masonry: 7c429b56da9d4ee0bbb3ed77a5ea710d6a5df39e
20 | MJExtension: 19bc33ce2eee2d319760f5622562cf581a6ff756
21 |
22 | PODFILE CHECKSUM: 4c339d2170dabdb62d78447c3e46d06ce767365a
23 |
24 | COCOAPODS: 1.5.3
25 |
--------------------------------------------------------------------------------
/AbuKlineView.xcworkspace/xcuserdata/haoji.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/AbuKlineView.xcworkspace/xcuserdata/jefferson.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/AbuKlineView.xcodeproj/xcuserdata/haoji.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | AbuKlineView.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 3B5D5BBC1F5F10A100C0E68B
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/AbuKlineView.xcodeproj/xcuserdata/jefferson.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | AbuKlineView.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 3B5D5BBC1F5F10A100C0E68B
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/AbuKlineView.xcodeproj/xcuserdata/jefferson.zhang.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | AbuKlineView.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 3B5D5BBC1F5F10A100C0E68B
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/Category/UIBezierPath+Extension.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIBezierPath+Extension.h
3 | // AbuKlineView
4 | //
5 | // Created by 阿布 on 17/9/6.
6 | // Copyright © 2017年 阿布. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UIBezierPath (Extension)
12 |
13 | + (UIBezierPath*)drawWireLine:(NSMutableArray*)linesArray;
14 |
15 |
16 | + (NSMutableArray<__kindof UIBezierPath*>*)drawLines:(NSMutableArray*)linesArray;
17 |
18 | + (UIBezierPath *)drawKLine:(CGFloat)open close:(CGFloat)close high:(CGFloat)high low:(CGFloat)low candleWidth:(CGFloat)candleWidth xPostion:(CGFloat)xPostion lineWidth:(CGFloat)lineWidth;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KLineCaculate/KLineCalculate.h:
--------------------------------------------------------------------------------
1 | //
2 | // KLineCalculate.h
3 | // ABuKLineChartView
4 | //
5 | // Created by jefferson on 2018/7/19.
6 | // Copyright © 2018年 jefferson. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | static NSString *const kMaxValue = @"kMaxValue";
12 | static NSString *const kMinValue = @"kMinValue";
13 |
14 | @interface KLineCalculate : NSObject
15 |
16 | + (instancetype)sharedInstance;
17 |
18 | - (NSDictionary *)calculateMaxAndMinValueWithDataArr:(NSArray *)dataArr;
19 |
20 | - (NSInteger)getTimesampIntervalWithRequestType:(NSString *)requestType timesamp:(NSInteger)lastKlineModelTimesamp;
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KLineLayer/KlineMALayer.h:
--------------------------------------------------------------------------------
1 | //
2 | // KlineMALayer.h
3 | // ABuKLineChartView
4 | //
5 | // Created by jefferson on 2018/9/7.
6 | // Copyright © 2018年 jefferson. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface KlineMALayer : CAShapeLayer
12 | - (instancetype)initQuotaDataArr:(NSArray *)dataArr candleWidth:(CGFloat)candleWidth candleSpace:(CGFloat)candleSpace startIndex:(CGFloat)startIndex maxValue:(CGFloat)maxValue heightPerpoint:(CGFloat)heightPerpoint totalHeight:(CGFloat)totalHeight lineWidth:(CGFloat)lineWidth lineColor:(UIColor *)lineColor wireType:(WIRETYPE)wiretype klineSubOrMain:(KlineWireSubOrMain)klineWiretype;
13 | @end
14 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/Category/UIView+Extension.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Extension.h
3 | // AbuKlineView
4 | //
5 | // Created by 阿布 on 17/9/6.
6 | // Copyright © 2017年 阿布. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UIView (Extension)
12 |
13 | @property (nonatomic, assign) CGFloat x;
14 | @property (nonatomic, assign) CGFloat y;
15 | @property (nonatomic, assign) CGFloat centerX;
16 | @property (nonatomic, assign) CGFloat centerY;
17 | @property (nonatomic, assign) CGFloat width;
18 | @property (nonatomic, assign) CGFloat height;
19 | @property (nonatomic, assign) CGFloat scrrenWidth;
20 | @property (nonatomic, assign) CGFloat scrrenHeight;
21 | @property (nonatomic, assign) CGSize size;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/AbuKlineView/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KlineCommonView/KlinePriceView.h:
--------------------------------------------------------------------------------
1 | //
2 | // KlinePriceView.h
3 | // ExchangeKline
4 | //
5 | // Created by jefferson on 2018/8/2.
6 | // Copyright © 2018年 jefferson. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface KlinePriceView : UIView
12 |
13 | @property (nonatomic,strong) NSArray *priceArr;
14 |
15 | - (instancetype)initWithFrame:(CGRect)frame PriceArr:(NSArray *)priceArr;
16 |
17 | - (void)reloadPriceWithPriceArr:(NSArray *)priceArr precision:(int)precision;
18 |
19 | - (void)hideZeroLabel:(BOOL)isHide;
20 |
21 | - (void)refreshCurrentPositionPricePositonY:(CGFloat)positionY price:(NSString *)price;
22 |
23 | - (void)refreshCurrentPositionPrice:(NSString *)price;
24 |
25 | - (void)updateFrameWithHeight:(CGFloat)height;
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KLineCaculate/KLineSubCalculate.h:
--------------------------------------------------------------------------------
1 | //
2 | // KLineSubCalculate.h
3 | // ABuKLineChartView
4 | //
5 | // Created by jefferson on 2018/7/19.
6 | // Copyright © 2018年 jefferson. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | typedef enum {
12 | SubATR = 0,
13 | SubBIAS = 1,
14 | SubCCI = 2,
15 | SubKD = 3,
16 | SubMACD = 4,
17 | SubRSI = 5,
18 | SubW_R = 6,
19 | SubARBR = 7,
20 | SubDKBY = 8,
21 | SubKDJ = 9,
22 | SubLW_R = 10, ///< _ -> &
23 | SubQHLSR = 11,
24 | }SubKPIType;
25 |
26 | @interface KLineSubCalculate : NSObject
27 |
28 | + (instancetype)sharedInstance;
29 | - (void)handleQuotaDataWithDataArr:(NSArray *)dataArr model:(KLineModel *)model index:(NSInteger)idx KPIType:(SubKPIType)type;;
30 | - (NSArray *)initializeQuotaDataWithArray:(NSArray *)dataArray KPIType:(SubKPIType)type;;
31 |
32 | @end
33 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KLineView/AbuCharViewProtocol.h:
--------------------------------------------------------------------------------
1 | //
2 | // AbuCharViewProtocol.h
3 | // AbuKlineView
4 | //
5 | // Created by 阿布 on 17/9/6.
6 | // Copyright © 2017年 阿布. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "KLineModel.h"
11 | @protocol AbuChartViewProtocol
12 |
13 | @optional
14 |
15 | - (void)displayScreenleftPostion:(CGFloat)leftPostion startIndex:(NSInteger)index count:(NSInteger)count;
16 |
17 | - (void)longPressCandleViewWithIndex:(NSInteger)kLineModeIndex kLineModel:(KLineModel *)kLineModel;
18 |
19 | - (void)displayLastModel:(KLineModel *)kLineModel;
20 |
21 | - (void)refreshCurrentPrice:(KLineModel *)kLineModel candleModel:(KLineModel *)candleModel;
22 |
23 | - (void)reloadPriceViewWithPriceArr:(NSArray *)priceArr;
24 |
25 | - (void)reloadPriceViewWithQuotaMaxValue:(double)maxValue MinValue:(double)minValue;
26 |
27 | - (void)displayMoreData;
28 |
29 | @end
30 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/Category/UIColor+Extension.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor+Extension.m
3 | // AbuKlineView
4 | //
5 | // Created by 阿布 on 17/9/6.
6 | // Copyright © 2017年 阿布. All rights reserved.
7 | //
8 |
9 | #import "UIColor+Extension.h"
10 |
11 | @implementation UIColor (Extension)
12 |
13 | +(UIColor *)colorWithHexString:(NSString *)color
14 | {
15 | NSString *str1 = [NSString stringWithFormat:@"0x%@",[color substringWithRange:NSMakeRange(1, 2)]];
16 | NSString *str2 = [NSString stringWithFormat:@"0x%@",[color substringWithRange:NSMakeRange(3, 2)]];
17 | NSString *str3 = [NSString stringWithFormat:@"0x%@",[color substringWithRange:NSMakeRange(5, 2)]];
18 |
19 | unsigned long f1 = strtoul([str1 UTF8String],0,16);
20 | unsigned long f2 = strtoul([str2 UTF8String],0,16);
21 | unsigned long f3 = strtoul([str3 UTF8String],0,16);
22 |
23 | return [UIColor colorWithRed:f1/255.0 green:f2/255.0 blue:f3/255.0 alpha:1.0];
24 | }
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AbuKlineView
2 | (CAShapelayer + UIBezierPath)绘制K线支撑横竖屏切换、刷新、长按、缩放、masonry适配,完美支持金融产品
3 |
4 | K线绘制(火币) 隐藏副图、成交量切换各种指标,logo水印,刷新,横竖屏,喜欢的可以star一波。有问题请添加QQ:2438100263 喜欢的可以添加群:362681337
5 | 
6 |
7 | 非常的流畅,占用内存少,使用矢量进行填充K线
8 |
9 | 
10 |
11 | 通过宏自定义K线,让你随心所欲定义K线高度,宽度,主图、幅图占比
12 | 
13 |
14 | 横竖屏完美适配(暂时没有适配iPhoneX)、随意切换
15 | 
16 |
17 |
18 |
19 |
20 | K线幅图指标计算(能与国际主流平台数据完美吻合,只给出部分指标计算(MACD,KDJ、WR 一般平台K线有这些幅图指标就差不多),由于其他原因暂不公开其他二十几种指标算法)
21 |
22 |
23 |
24 | 后面将继续优化刷新逻辑、添加分时图、各种周期图的切换。
25 | 本GitHub已有GCDAsynSocket与Websocket的demo,行情尽在你的眼前,喜欢的给个star哦,谢谢!
26 |
27 | 喜欢的可以打赏一下,交流炒股心得
28 | 
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KLineView/AbuCandChartView.h:
--------------------------------------------------------------------------------
1 | //
2 | // AbuCandChartView.h
3 | // AbuKlineView
4 | //
5 | // Created by 阿布 on 17/9/7.
6 | // Copyright © 2017年 阿布. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AbuCandChartView : UIView
12 | @property (nonatomic,strong) NSMutableArray<__kindof KLineModel*> * dataArray;
13 | @property (nonatomic,assign) CGFloat candleSpace;
14 | @property (nonatomic,assign) CGFloat candleWidth;
15 | @property (nonatomic,assign) NSInteger currentStartIndex;
16 | @property (nonatomic,assign) CGFloat contentOffset;
17 | @property (nonatomic,assign) BOOL kvoEnable;
18 | @property (nonatomic,assign) BOOL hollowRise;
19 |
20 | - (CGPoint)getLongPressModelPostionWithXPostion:(CGFloat)xPostion;
21 | - (void)reloadKline;
22 | - (void)calcuteCandleWidth;
23 | - (void)updateWidth;
24 | - (void)drawKLine;
25 | - (void)drawPresetQuota:(KlineSubKPIType)presetQuotaName;
26 | - (void)refreshKLineView:(KLineModel *)model;
27 | @property (nonatomic,weak) id delegate;
28 | @property (nonatomic,assign) DataLineType currentType;
29 | @end
30 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KLineTitleView/KlineTitleView.h:
--------------------------------------------------------------------------------
1 | //
2 | // KlineTitleView.h
3 | // LGTS2
4 | //
5 | // Created by Jefferson.zhang on 2017/7/18.
6 | // Copyright © 2017年 Mata. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | typedef enum
12 | {
13 | K_LINE_5MIN = 0x01, // 5分钟
14 | K_LINE_15MIN = 0x02, // 15分钟
15 | K_LINE_30MIN = 0x03, // 30分钟
16 | K_LINE_60MIN = 0x04, // 60分钟
17 | K_LINE_DAY = 0x05, //日线
18 | K_LINE_WEEK = 0x06, // 周线
19 | K_LINE_MONTH = 0x07, // 月线
20 | K_LINE_VANE = 0x08, // 风向标
21 | K_LINE_YEAR = 0x09, // 年线
22 | K_LINE_MANY_DAY = 15, // 多日线
23 | K_LINE_MANY_MIN = 16, // 多分钟线
24 | K_LINE_MANY_HOUR = 17, // 多小时线
25 | K_LINE_1MIN = 34, // 1分时图
26 | K_LINE_MIN = 35, // 分钟线
27 | K_LINE_3MIN = 36, // 3分钟
28 | K_LINE_1HOUR = 37, // 1小时
29 | K_LINE_4HOUR = 38, // 4小时
30 |
31 | }KLINETYPE;
32 |
33 | @protocol KlineTitleViewDelegate
34 | - (void)selectIndex:(KLINETYPE)type;
35 |
36 | @end
37 |
38 | @interface KlineTitleView : UIView
39 |
40 | @property (nonatomic, weak) id delegate;
41 |
42 | - (instancetype)initWithklineTitleArray:(NSArray *)titleArray typeArray:(NSArray *)typeArray;
43 |
44 |
45 |
46 | @end
47 |
--------------------------------------------------------------------------------
/AbuKlineView/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationLandscapeLeft
34 | UIInterfaceOrientationLandscapeRight
35 | UIInterfaceOrientationPortrait
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/AbuKlineView/BaseViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // BaseViewController.m
3 | // AbuKline
4 | //
5 | // Created by jefferson on 2018/8/27.
6 | // Copyright © 2018年 jefferson. All rights reserved.
7 | //
8 |
9 | #import "BaseViewController.h"
10 | #import "AppDelegate.h"
11 |
12 | @interface BaseViewController ()
13 |
14 | @end
15 |
16 | @implementation BaseViewController
17 |
18 | - (void)viewDidLoad {
19 | [super viewDidLoad];
20 | // Do any additional setup after loading the view.
21 | [self supportRotion:UIInterfaceOrientationPortrait];
22 | }
23 | - (void)supportRotion:(int)rotion
24 | {
25 | NSNumber *value = [NSNumber numberWithInt:rotion];
26 | [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
27 | }
28 |
29 | - (void)viewDidAppear:(BOOL)animated
30 | {
31 | [super viewDidAppear:animated];
32 |
33 | ((AppDelegate *)[UIApplication sharedApplication].delegate).allowRotation = NO;
34 |
35 | }
36 |
37 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
38 | {
39 | return NO;
40 | }
41 |
42 | #if __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_9_0
43 | - (NSUInteger)supportedInterfaceOrientations
44 | #else
45 | - (UIInterfaceOrientationMask)supportedInterfaceOrientations
46 | #endif
47 | {
48 | return UIInterfaceOrientationMaskPortrait;
49 | }
50 |
51 |
52 |
53 | - (BOOL)prefersStatusBarHidden
54 | {
55 | return NO;
56 | }
57 |
58 | - (BOOL)shouldAutorotate
59 | {
60 | return NO;
61 | }
62 |
63 |
64 | @end
65 |
--------------------------------------------------------------------------------
/AbuKlineView/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineModel/KLineModel.m:
--------------------------------------------------------------------------------
1 | //
2 | // KLineModel.m
3 | // ABuKLineChartView
4 | //
5 | // Created by jefferson on 2018/7/19.
6 | // Copyright © 2018年 jefferson. All rights reserved.
7 | //
8 |
9 | #import "KLineModel.h"
10 |
11 | static NSString *const kRise = @"kRise";
12 | static NSString *const kDrop = @"kDrop";
13 |
14 | @implementation KLineModel
15 |
16 | - (void)initData
17 | {
18 |
19 | [self EMA12];
20 | [self EMA26];
21 | [self DIF];
22 | [self DEA];
23 | [self MACD];
24 | }
25 |
26 | - (void)reInitData
27 | {
28 | NSInteger SHORT = 12;
29 | NSInteger LONG = 26;
30 | NSInteger M = 9;
31 |
32 | self.EMA12 = @((2.0 * self.closePrice + (SHORT - 1) *(self.previousKlineModel.EMA12.doubleValue))/(SHORT + 1));
33 | self.EMA26 = @((2 * self.closePrice + (LONG -1) * self.previousKlineModel.EMA26.doubleValue)/(LONG + 1));
34 | self.DIF = @(self.EMA12.doubleValue - self.EMA26.doubleValue);
35 | self.DEA = @(self.previousKlineModel.DEA.doubleValue * (M-1)/(M+1) + 2.0 / (M+1) *self.DIF.doubleValue);
36 | self.MACD = @(2*(self.DIF.doubleValue - self.DEA.doubleValue));
37 |
38 | }
39 |
40 | - (void)reInitKDJData
41 | {
42 |
43 | self.RSV_9 = @((self.closePrice - self.LNinePrice.doubleValue)/(self.HNinePrice.doubleValue-self.LNinePrice.doubleValue)*100);
44 |
45 |
46 | double previousK = 0;
47 | if (self.xPoint==8) {
48 |
49 | previousK = 50;
50 | }else{
51 | previousK = self.previousKlineModel.KDJ_K.doubleValue;
52 | }
53 | self.KDJ_K = @(previousK*2/3.0+1/3.0*self.RSV_9.doubleValue);
54 |
55 |
56 | double previousD = 0;
57 | if (self.xPoint==8) {
58 |
59 | previousD = 50;
60 | }else{
61 | previousD = self.previousKlineModel.KDJ_D.doubleValue;
62 | }
63 | self.KDJ_D = @(previousD*2/3.0+1/3.0*self.KDJ_K.doubleValue);
64 |
65 |
66 | self.KDJ_J = @(3*self.KDJ_K.doubleValue-2*self.KDJ_D.doubleValue);
67 |
68 | if (isnan(self.KDJ_K.doubleValue)) {
69 | self.KDJ_K = self.previousKlineModel.KDJ_K;
70 |
71 | }
72 | if (isnan(self.KDJ_D.doubleValue)) {
73 |
74 | self.KDJ_D = self.previousKlineModel.KDJ_D;
75 | }
76 | if (isnan(self.KDJ_J.doubleValue)) {
77 |
78 | self.KDJ_J = self.previousKlineModel.KDJ_J;
79 | }
80 | }
81 |
82 |
83 | @end
84 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/Category/UIView+Extension.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Extension.m
3 | // AbuKlineView
4 | //
5 | // Created by 阿布 on 17/9/6.
6 | // Copyright © 2017年 阿布. All rights reserved.
7 | //
8 |
9 | #import "UIView+Extension.h"
10 |
11 | @implementation UIView (Extension)
12 |
13 | -(void)setX:(CGFloat)x
14 | {
15 | CGRect tempF = self.frame;
16 | tempF.origin.x = x;
17 | self.frame = tempF;
18 | }
19 |
20 | -(CGFloat)x
21 | {
22 | return self.frame.origin.x;
23 | }
24 |
25 | -(void)setY:(CGFloat)y{
26 | CGRect tempF = self.frame;
27 | tempF.origin.y = y ;
28 | self.frame = tempF;
29 | }
30 |
31 | -(CGFloat)y
32 | {
33 | return self.frame.origin.y;
34 | }
35 |
36 | -(void)setWidth:(CGFloat)width
37 | {
38 | CGRect tempF = self.frame;
39 | tempF.size.width = width;
40 | self.frame = tempF;
41 | }
42 |
43 | -(void)setCenterX:(CGFloat)centerX
44 | {
45 | CGPoint tempF = self.center;
46 | tempF.x = centerX;
47 | self.center = tempF;
48 | }
49 | -(CGFloat)centerX
50 | {
51 | return self.center.x;
52 | }
53 |
54 | -(void)setCenterY:(CGFloat)centerY
55 | {
56 | CGPoint tempF = self.center;
57 | tempF.y = centerY;
58 | self.center = tempF;
59 | }
60 | -(CGFloat)centerY
61 | {
62 | return self.center.y;
63 | }
64 |
65 | -(CGFloat)width
66 | {
67 | return self.frame.size.width;
68 | }
69 |
70 | -(void)setHeight:(CGFloat)height
71 | {
72 | CGRect tempF = self.frame;
73 | tempF.size.height = height;
74 | self.frame = tempF;
75 | }
76 |
77 | -(CGFloat)height
78 | {
79 | return self.frame.size.height;
80 | }
81 |
82 | - (void)setScrrenWidth:(CGFloat)scrrenWidth
83 | {
84 | CGRect tempF = self.frame;
85 | tempF.size.width = scrrenWidth;
86 | self.frame = tempF;
87 | }
88 |
89 | - (CGFloat)scrrenWidth
90 | {
91 | return self.frame.size.width;
92 | }
93 |
94 | - (void)setScrrenHeight:(CGFloat)scrrenHeight
95 | {
96 | CGRect tempF = self.frame;
97 | tempF.size.height = scrrenHeight;
98 | self.frame = tempF;
99 | }
100 |
101 | -(CGFloat)scrrenHeight
102 | {
103 | return self.frame.size.height;
104 | }
105 |
106 | -(void)setSize:(CGSize)size
107 | {
108 | CGRect tempF = self.frame;
109 | tempF.size = size;
110 | self.frame = tempF;
111 | }
112 | -(CGSize)size
113 | {
114 | return self.frame.size;
115 | }
116 |
117 | @end
118 |
119 |
--------------------------------------------------------------------------------
/AbuKlineView/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // AbuKlineView
4 | //
5 | // Created by 阿布 on 17/9/6.
6 | // Copyright © 2017年 阿布. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @interface AppDelegate ()
12 |
13 | @end
14 |
15 | @implementation AppDelegate
16 |
17 |
18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
19 | // Override point for customization after application launch.
20 | return YES;
21 | }
22 |
23 |
24 | - (void)applicationWillResignActive:(UIApplication *)application {
25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
27 | }
28 |
29 |
30 | - (void)applicationDidEnterBackground:(UIApplication *)application {
31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
33 | }
34 |
35 |
36 | - (void)applicationWillEnterForeground:(UIApplication *)application {
37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
38 | }
39 |
40 |
41 | - (void)applicationDidBecomeActive:(UIApplication *)application {
42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
43 | }
44 |
45 |
46 | - (void)applicationWillTerminate:(UIApplication *)application {
47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
48 | }
49 |
50 | - (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window{
51 |
52 | if (self.allowRotation) {
53 |
54 | return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortrait ;
55 |
56 | }
57 | return UIInterfaceOrientationMaskPortrait;
58 | }
59 |
60 | @end
61 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KLineCaculate/KLineSubCalculate.m:
--------------------------------------------------------------------------------
1 | //
2 | // KLineSubCalculate.m
3 | // ABuKLineChartView
4 | //
5 | // Created by jefferson on 2018/7/19.
6 | // Copyright © 2018年 jefferson. All rights reserved.
7 | //
8 |
9 | #import "KLineSubCalculate.h"
10 | #import "KLineModel.h"
11 |
12 | static NSString *const kRise = @"kRise";
13 | static NSString *const kDrop = @"kDrop";
14 |
15 | @implementation KLineSubCalculate
16 |
17 | static id _instance;
18 |
19 | + (instancetype)sharedInstance
20 | {
21 | static dispatch_once_t onceToken;
22 | dispatch_once(&onceToken, ^{
23 | _instance = [[self alloc] init];
24 | });
25 | return _instance;
26 | }
27 | - (NSArray *)initializeQuotaDataWithArray:(NSArray *)dataArray KPIType:(SubKPIType)type
28 | {
29 | __weak typeof(self) weakSelf = self;
30 | [dataArray enumerateObjectsUsingBlock:^(KLineModel *model, NSUInteger idx, BOOL * _Nonnull stop) {
31 |
32 | [weakSelf handleQuotaDataWithDataArr:dataArray model:model index:idx KPIType:type];
33 |
34 | }];
35 | return dataArray;
36 | }
37 |
38 | - (void)handleQuotaDataWithDataArr:(NSArray *)dataArr model:(KLineModel *)model index:(NSInteger)idx KPIType:(SubKPIType)type
39 | {
40 | if (type == SubMACD) {
41 | [self calculateMACDWithDataArr:dataArr model:model index:idx];
42 | [self calculateMAWithDataArr:dataArr num:5 model:model index:idx];
43 | [self calculateMAWithDataArr:dataArr num:10 model:model index:idx];
44 | [self calculateMAWithDataArr:dataArr num:20 model:model index:idx];
45 |
46 | }
47 | }
48 |
49 | - (void)calculateMACDWithDataArr:(NSArray *)dataArr model:(KLineModel *)model index:(NSInteger)idx
50 | {
51 | KLineModel *previousKlineModel = [KLineModel new];
52 | if (idx>0&&idx=num-1) {
65 | for (int i = 0; i *)drawLines:(NSMutableArray *)linesArray
32 | {
33 | if (IsArrayNull(linesArray))
34 | return nil;
35 | NSMutableArray * result = [NSMutableArray array];
36 |
37 | for (NSMutableArray * lineArray in linesArray) {
38 | UIBezierPath * path = [UIBezierPath drawWireLine:lineArray];
39 | [result addObject:path];
40 | }
41 |
42 | return result;
43 |
44 | }
45 |
46 | + (UIBezierPath *)drawKLine:(CGFloat)open close:(CGFloat)close high:(CGFloat)high low:(CGFloat)low candleWidth:(CGFloat)candleWidth xPostion:(CGFloat)xPostion lineWidth:(CGFloat)lineWidth
47 | {
48 | UIBezierPath * candlePath = [UIBezierPath bezierPath];
49 | candlePath.lineWidth = lineWidth;
50 | CGFloat y = open > close ? close : open;
51 | CGFloat height = fabs(close-open);
52 | [candlePath moveToPoint:CGPointMake(xPostion, y)];
53 | [candlePath addLineToPoint:CGPointMake(xPostion + candleWidth / 2.0f, y)];
54 | if (y > high) {
55 | [candlePath addLineToPoint:CGPointMake(xPostion + candleWidth / 2.0f, high)];
56 | [candlePath addLineToPoint:CGPointMake(xPostion + candleWidth / 2.0f, y)];
57 | }
58 |
59 | [candlePath addLineToPoint:CGPointMake(xPostion + candleWidth, y)];
60 | [candlePath addLineToPoint:CGPointMake(xPostion + candleWidth, y + height)];
61 | [candlePath addLineToPoint:CGPointMake(xPostion + candleWidth / 2.0f, y + height)];
62 | if ((y + height) < low)
63 | {
64 | [candlePath addLineToPoint:CGPointMake(xPostion + candleWidth / 2.0f, low)];
65 | [candlePath addLineToPoint:CGPointMake(xPostion + candleWidth / 2.0f, y+height)];
66 | }
67 | [candlePath addLineToPoint:CGPointMake(xPostion, y + height)];
68 | [candlePath addLineToPoint:CGPointMake(xPostion, y)];
69 | [candlePath closePath];
70 | return candlePath;
71 | }
72 |
73 | @end
74 |
--------------------------------------------------------------------------------
/AbuKlineView/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KLineLayer/KlineTimeLayer.m:
--------------------------------------------------------------------------------
1 | //
2 | // KlineTimeLayer.m
3 | // ABuKLineChartView
4 | //
5 | // Created by jefferson on 2018/9/7.
6 | // Copyright © 2018年 jefferson. All rights reserved.
7 | //
8 |
9 | #import "KlineTimeLayer.h"
10 |
11 | @interface KlineTimeLayer()
12 | @property (nonatomic, strong) NSArray * klineDataSource;
13 | @property (nonatomic,assign) double height;
14 | @property (nonatomic,assign) CGFloat candleWidth;
15 | @property (nonatomic,assign) double timeHeight;
16 | @property (nonatomic,assign) double bottomMargin;
17 | @property (nonatomic,assign) double lineWidth;
18 |
19 | @end
20 |
21 | @implementation KlineTimeLayer
22 |
23 | - (instancetype)initQuotaDataArr:(NSArray *)dataArr candleWidth:(CGFloat)candleWidth height:(CGFloat)height timeHight:(CGFloat)timeHeight bottomMargin:(CGFloat)bottomMargin lineWidth:(CGFloat)lineWidth
24 | {
25 | self = [super init];
26 | if (self) {
27 | self.klineDataSource = dataArr;
28 | self.candleWidth = candleWidth;
29 | self.height = height;
30 | self.timeHeight = timeHeight;
31 | self.bottomMargin = bottomMargin;
32 | self.lineWidth = lineWidth;
33 | [self drawTimeLayer];
34 | }
35 | return self;
36 | }
37 |
38 | - (void)drawTimeLayer
39 | {
40 | [self.klineDataSource enumerateObjectsUsingBlock:^(KLineModel *model, NSUInteger idx, BOOL * _Nonnull stop) {
41 |
42 | if (model.isDrawDate)
43 | {
44 | CATextLayer *layer = [self getTextLayer];
45 | layer.string = model.timeStr;
46 | if (model.highestPoint.x <= 0.00001f)
47 | {
48 | layer.frame = CGRectMake(0, self.height - timeheight, 80, timeheight);
49 |
50 | }
51 |
52 | else
53 | {
54 | layer.position = CGPointMake(model.highestPoint.x + self.candleWidth, self.height - timeheight/2 - self.bottomMargin);
55 | layer.bounds = CGRectMake(0, 0, 80, timeheight);
56 |
57 | }
58 | [self addSublayer:layer];
59 |
60 | CAShapeLayer *lineLayer = [self getAxispLayer];
61 | UIBezierPath *path = [UIBezierPath bezierPath];
62 | path.lineWidth = self.lineWidth;
63 | lineLayer.lineWidth = self.lineWidth;
64 |
65 | [path moveToPoint:CGPointMake(model.highestPoint.x + self.candleWidth/2 - self.lineWidth/2, 1*heightradio)];
66 | [path addLineToPoint:CGPointMake(model.highestPoint.x + self.candleWidth/2 - self.lineWidth/2 ,self.height - timeheight- self.bottomMargin)];
67 | lineLayer.path = path.CGPath;
68 | lineLayer.lineDashPattern = @[@6,@10];
69 | [self addSublayer:lineLayer];
70 | }
71 | }];
72 | }
73 |
74 | - (CATextLayer*)getTextLayer
75 | {
76 | CATextLayer *layer = [CATextLayer layer];
77 | layer.contentsScale = [UIScreen mainScreen].scale;
78 | layer.fontSize = 12.f;
79 | layer.alignmentMode = kCAAlignmentLeft;
80 | layer.foregroundColor =
81 | [UIColor grayColor].CGColor;
82 | return layer;
83 | }
84 |
85 | - (CAShapeLayer*)getAxispLayer
86 | {
87 | CAShapeLayer *layer = [CAShapeLayer layer];
88 | layer.strokeColor = [UIColor colorWithHexString:@"#ededed"].CGColor;
89 | layer.fillColor = [[UIColor clearColor] CGColor];
90 | layer.contentsScale = [UIScreen mainScreen].scale;
91 | return layer;
92 | }
93 |
94 | @end
95 |
--------------------------------------------------------------------------------
/AbuKlineView.xcodeproj/xcuserdata/haoji.xcuserdatad/xcschemes/AbuKlineView.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/AbuKlineView.xcodeproj/xcuserdata/jefferson.xcuserdatad/xcschemes/AbuKlineView.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/AbuKlineView.xcodeproj/xcuserdata/jefferson.zhang.xcuserdatad/xcschemes/AbuKlineView.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KlineCommonView/KlineCurrentPriceView.m:
--------------------------------------------------------------------------------
1 | //
2 | // KlineCurrentPriceView.m
3 | // ABuKLineChartView
4 | //
5 | // Created by jefferson on 2018/9/14.
6 | // Copyright © 2018年 jefferson. All rights reserved.
7 | //
8 |
9 | #import "KlineCurrentPriceView.h"
10 | #define CoordinateDisPlayLabelColor [UIColor clearColor]
11 | @interface KlineCurrentPriceView()
12 | @property (nonatomic,strong) UIView * currentPriceLine;
13 | @property (nonatomic,strong) UILabel * priceLabel;
14 | @property (nonatomic,assign) BOOL update;
15 | @property (nonatomic,strong) CAShapeLayer * horizontalLineLayer;
16 | @end
17 |
18 | @implementation KlineCurrentPriceView
19 |
20 | - (instancetype)initWithUpdate:(BOOL)update
21 | {
22 | self = [super init];
23 | if (self) {
24 | self.update = update;
25 | [self buildUI];
26 | [self addConstrains];
27 | }
28 | return self;
29 | }
30 |
31 | - (void)buildUI
32 | {
33 |
34 | self.currentPriceLine = [[UIView alloc] init];
35 | if (self.update) {
36 | self.currentPriceLine.backgroundColor = [UIColor clearColor];
37 | [self.currentPriceLine.layer addSublayer:[self creatLayerWithColor:CoordinateDisPlayLabelColor]];
38 | }else{
39 | self.currentPriceLine.backgroundColor = CoordinateDisPlayLabelColor;
40 | }
41 | [self addSubview:self.currentPriceLine];
42 | self.priceLabel = [[UILabel alloc] init];
43 | self.priceLabel.lineBreakMode = NSLineBreakByWordWrapping;
44 | self.priceLabel.backgroundColor = CoordinateDisPlayLabelColor;
45 | self.priceLabel.text = @"";
46 | self.priceLabel.textColor = [UIColor whiteColor];
47 | self.priceLabel.textAlignment = NSTextAlignmentCenter;
48 | self.priceLabel.font = [UIFont systemFontOfSize:9];
49 | [self addSubview:self.priceLabel];
50 |
51 | }
52 |
53 | - (CAShapeLayer *)creatLayerWithColor:(UIColor *)color
54 | {
55 | [self.horizontalLineLayer removeFromSuperlayer];
56 | self.horizontalLineLayer = nil;
57 | self.horizontalLineLayer = [CAShapeLayer layer];
58 | UIBezierPath *topLine = [UIBezierPath bezierPath];
59 | [topLine moveToPoint:CGPointMake(0,0)];
60 | if (!Portrait) {
61 | [topLine addLineToPoint:CGPointMake(KSCREEN_HEIGHT - priceWidth,0)];
62 | }else{
63 | [topLine addLineToPoint:CGPointMake(KSCREEN_WIDTH - priceWidth,0)];
64 | }
65 | self.horizontalLineLayer.lineWidth = 1;
66 | self.horizontalLineLayer.lineDashPattern = @[@4, @4];
67 | self.horizontalLineLayer.path = topLine.CGPath;
68 | self.horizontalLineLayer.strokeColor = color.CGColor;
69 | return self.horizontalLineLayer;
70 | }
71 |
72 | - (void)addConstrains
73 | {
74 | [self.currentPriceLine mas_makeConstraints:^(MASConstraintMaker *make) {
75 | make.right.mas_equalTo(self).offset(-priceWidth);
76 | make.left.mas_equalTo(self);
77 | make.height.equalTo(@0.5);
78 | make.centerY.mas_equalTo(self);
79 |
80 | }];
81 | [self.priceLabel mas_makeConstraints:^(MASConstraintMaker *make) {
82 | make.left.mas_equalTo(self.currentPriceLine.mas_right);
83 | make.right.mas_equalTo(self.mas_right);
84 | make.height.mas_equalTo(14);
85 | make.centerY.mas_equalTo(self);
86 | }];
87 | }
88 |
89 | - (void)updateNewPrice:(NSString *)newPrice backgroundColor:(UIColor *)color precision:(int)precision
90 | {
91 |
92 | NSString *priceStrr = [NSString stringWithFormat:@"%.*f",precision,[newPrice doubleValue]];
93 |
94 | self.priceLabel.text = priceStrr;
95 | if (color) {
96 |
97 | self.priceLabel.backgroundColor = color;
98 | if (self.update)
99 | self.currentPriceLine.backgroundColor = [UIColor clearColor];
100 | [self.currentPriceLine.layer addSublayer:[self creatLayerWithColor:color]];
101 | }
102 | }
103 |
104 | @end
105 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KLineLayer/KlineCandelLayer.m:
--------------------------------------------------------------------------------
1 | //
2 | // KlineCandelLayer.m
3 | // ABuKLineChartView
4 | //
5 | // Created by jefferson on 2018/9/7.
6 | // Copyright © 2018年 jefferson. All rights reserved.
7 | //
8 |
9 | #import "KlineCandelLayer.h"
10 |
11 | @interface KlineCandelLayer()
12 |
13 | @property (nonatomic, strong) NSArray * klineDataSource;
14 | @property (nonatomic,assign) double heightPerpoint;
15 | @property (nonatomic,assign) CGFloat candleWidth;
16 | @property (nonatomic,assign) CGFloat candleSpace;
17 | @property (nonatomic,assign) CGFloat startIndex;
18 | @property (nonatomic,assign) double maxValue;
19 | @property (nonatomic,assign) double contentWidth;
20 | @end
21 | @implementation KlineCandelLayer
22 | - (instancetype)initQuotaDataArr:(NSArray *)dataArr candleWidth:(CGFloat)candleWidth candleSpace:(CGFloat)candleSpace startIndex:(CGFloat)startIndex maxValue:(CGFloat)maxValue heightPerpoint:(CGFloat)heightPerpoint scrollViewContentWidth:(CGFloat)contentWidth
23 | {
24 | self = [super init];
25 | if (self) {
26 | self.klineDataSource = dataArr;
27 | self.candleWidth = candleWidth;
28 | self.candleSpace = candleSpace;
29 | self.startIndex = startIndex;
30 | self.maxValue = maxValue;
31 | self.heightPerpoint = heightPerpoint;
32 | self.contentWidth = contentWidth;
33 | [self convertToKlinePositionDataArr:self.klineDataSource];
34 | [self drawCandleSublayers];
35 | }
36 | return self;
37 | }
38 |
39 | - ( void)convertToKlinePositionDataArr:(NSArray *)dataArr
40 | {
41 | for (NSInteger i = 0 ; i < dataArr.count; i++)
42 | {
43 | KLineModel *model = [dataArr objectAtIndex:i];
44 | CGFloat open = ((self.maxValue - model.openPrice) * self.heightPerpoint);
45 | CGFloat close = ((self.maxValue - model.closePrice) * self.heightPerpoint);
46 | CGFloat high = ((self.maxValue - model.highPrice) * self.heightPerpoint);
47 | CGFloat low = ((self.maxValue - model.lowPrice) * self.heightPerpoint);
48 | CGFloat left = self.startIndex + ((self.candleWidth + self.candleSpace) * i);
49 |
50 | if (left >= self.contentWidth)
51 | {
52 | left = self.contentWidth - self.candleWidth/2.f;
53 | }
54 | model.opensPoint = CGPointMake(left, open);
55 | model.closesPoint = CGPointMake(left, close);
56 | model.highestPoint = CGPointMake(left, high);
57 | model.lowestPoint = CGPointMake(left, low);
58 | }
59 | }
60 |
61 | - (CAShapeLayer*)getShaperLayer:(KLineModel*)postion
62 | {
63 | CGFloat openPrice = postion.opensPoint.y + topDistance;
64 | CGFloat closePrice = postion.closesPoint.y + topDistance;
65 | CGFloat hightPrice = postion.highestPoint.y + topDistance;
66 | CGFloat lowPrice = postion.lowestPoint.y + topDistance;
67 | CGFloat x = postion.opensPoint.x;
68 | UIBezierPath *path = [UIBezierPath drawKLine:openPrice close:closePrice high:hightPrice low:lowPrice candleWidth:self.candleWidth xPostion:x lineWidth:self.lineWidth];
69 |
70 | CAShapeLayer *subLayer = [CAShapeLayer layer];
71 | subLayer.fillColor = [UIColor clearColor].CGColor;
72 | if (postion.opensPoint.y >= postion.closesPoint.y)
73 | {
74 | subLayer.strokeColor = RISECOLOR.CGColor;
75 | // subLayer.fillColor = RISECOLOR.CGColor;
76 | }
77 | else
78 | {
79 | subLayer.strokeColor = DROPCOLOR.CGColor;
80 | // subLayer.fillColor = DROPCOLOR.CGColor;
81 | }
82 | subLayer.path = path.CGPath;
83 | [path removeAllPoints];
84 | return subLayer;
85 | }
86 |
87 | - (void)drawCandleSublayers
88 | {
89 | WS(weakSelf);
90 | [self.klineDataSource enumerateObjectsUsingBlock:^(KLineModel *obj, NSUInteger idx, BOOL * _Nonnull stop) {
91 | CAShapeLayer *subLayer = [weakSelf getShaperLayer:obj];
92 | [weakSelf addSublayer:subLayer];
93 | }];
94 | }
95 |
96 | @end
97 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KLineLayer/KlineQuotaColumnLayer.m:
--------------------------------------------------------------------------------
1 | //
2 | // KlineQuotaColumnLayer.m
3 | // ABuKLineChartView
4 | //
5 | // Created by jefferson on 2018/9/10.
6 | // Copyright © 2018年 jefferson. All rights reserved.
7 | //
8 |
9 | #import "KlineQuotaColumnLayer.h"
10 |
11 | static inline bool macdIsEqualZero(float value)
12 | {
13 | return fabsf(value) <= 0.00001f;
14 | }
15 |
16 | static NSString *const macdStartX = @"macdStartX";
17 | static NSString *const macdStartY = @"macdStartY";
18 | static NSString *const macdEndX = @"macdEndX";
19 | static NSString *const macdEndY = @"macdEndY";
20 |
21 | @interface KlineQuotaColumnLayer()
22 |
23 | @property (nonatomic, strong) NSArray * klineDataSource;
24 | @property (nonatomic,assign) double heightPerpoint;
25 | @property (nonatomic,assign) CGFloat candleWidth;
26 | @property (nonatomic,assign) CGFloat candleSpace;
27 | @property (nonatomic,assign) CGFloat startIndex;
28 | @property (nonatomic,assign) CGFloat maxValue;
29 | @property (nonatomic,assign) CGFloat qutoaHeight;
30 | @end
31 |
32 | @implementation KlineQuotaColumnLayer
33 |
34 | - (instancetype)initQuotaDataArr:(NSArray *)dataArr candleWidth:(CGFloat)candleWidth candleSpace:(CGFloat)candleSpace startIndex:(CGFloat)startIndex maxValue:(CGFloat)maxValue heightPerpoint:(CGFloat)heightPerpoint qutoaHeight:(CGFloat)qutoaHeight
35 | {
36 | self = [super init];
37 | if (self) {
38 | self.klineDataSource = dataArr;
39 | self.heightPerpoint = heightPerpoint;
40 | self.candleWidth = candleWidth;
41 | self.candleSpace = candleSpace;
42 | self.maxValue = maxValue;
43 | self.startIndex = startIndex;
44 | self.qutoaHeight = qutoaHeight;
45 | [self drawMacdLayer:[self coverMacdPostions]];
46 | }
47 | return self;
48 | }
49 |
50 | - (NSMutableArray *)coverMacdPostions
51 | {
52 | NSMutableArray * postions = [NSMutableArray array];
53 | for (int i = 0; i < self.klineDataSource.count; ++i) {
54 | NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
55 | KLineModel *model = [self.klineDataSource objectAtIndex:i];
56 | CGFloat xPosition = self.startIndex + ((self.candleSpace+self.candleWidth) * i);
57 | CGFloat yPosition = ABS((self.maxValue - [model.MACD floatValue])/self.heightPerpoint);
58 | dictionary[macdEndX] = @(xPosition);
59 | dictionary[macdEndY] = @(yPosition);
60 | CGPoint strartPoint = CGPointMake(xPosition,self.maxValue/self.heightPerpoint);
61 | dictionary[macdStartX] = @(strartPoint.x);
62 | dictionary[macdStartY] = @(strartPoint.y);
63 | float x = strartPoint.y - yPosition;
64 | if (macdIsEqualZero(x))
65 | {
66 | dictionary[macdEndY] = @(self.maxValue/self.heightPerpoint+1);
67 | }
68 | [postions addObject:dictionary];
69 | }
70 | return postions;
71 | }
72 |
73 | - (void)drawMacdLayer:(NSMutableArray *)postions
74 | {
75 | [postions enumerateObjectsUsingBlock:^(NSDictionary* dic, NSUInteger idx, BOOL * _Nonnull stop) {
76 | CGFloat strartX = [dic[macdStartX] floatValue];
77 | CGFloat strartY = [dic[macdStartY] floatValue];
78 | CGFloat endY = [dic[macdEndY] floatValue];
79 | CGRect rect = CGRectMake(strartX, strartY + self.qutoaHeight + midDistance, self.candleWidth, endY- strartY);
80 | UIBezierPath *path = [UIBezierPath bezierPathWithRect:rect];
81 | CAShapeLayer * subLayer = [CAShapeLayer layer];
82 | subLayer.path = path.CGPath;
83 |
84 | if (endY > strartY)
85 | {
86 | subLayer.strokeColor = DROPCOLOR.CGColor;
87 |
88 | subLayer.fillColor = DROPCOLOR.CGColor;
89 | }
90 | else
91 | {
92 | subLayer.strokeColor = RISECOLOR.CGColor;
93 | subLayer.fillColor = RISECOLOR.CGColor;
94 | }
95 | [self addSublayer:subLayer];
96 | }];
97 | }
98 |
99 | @end
100 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KLineCaculate/KLineCalculate.m:
--------------------------------------------------------------------------------
1 | //
2 | // KLineCalculate.m
3 | // ABuKLineChartView
4 | //
5 | // Created by jefferson on 2018/7/19.
6 | // Copyright © 2018年 jefferson. All rights reserved.
7 | //
8 |
9 | #import "KLineCalculate.h"
10 |
11 | @implementation KLineCalculate
12 |
13 | static id _instance;
14 |
15 | + (instancetype)sharedInstance
16 | {
17 | static dispatch_once_t onceToken;
18 | dispatch_once(&onceToken, ^{
19 | _instance = [[self alloc] init];
20 | });
21 | return _instance;
22 | }
23 | - (NSDictionary *)calculateMaxAndMinValueWithDataArr:(NSArray *)dataArr
24 | {
25 | NSMutableArray *calculateArr = [NSMutableArray array];
26 | for (NSObject *item in dataArr) {
27 | if ([item isKindOfClass:[NSArray class]]) {
28 |
29 | [calculateArr addObjectsFromArray:(NSArray *)item];
30 | }else{
31 |
32 | [calculateArr addObject:item];
33 | }
34 | }
35 | __block double maxValue = 0;
36 | __block double minValue = 0;
37 | NSMutableDictionary *resultDic = [NSMutableDictionary dictionary];
38 | [calculateArr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
39 |
40 | double value = [obj doubleValue];
41 | if (idx==0) {
42 |
43 | maxValue = value;
44 | minValue = value;
45 | }else{
46 |
47 | if (value>maxValue) {
48 | maxValue = value;
49 | }else if (value
15 | #import
16 | #import
17 |
18 | #import "KlineTitleView.h"
19 | #import "AbuCharViewProtocol.h"
20 | #import "AbuKlineView.h"
21 | #import "KLineModel.h"
22 | #import "KLineCalculate.h"
23 | #import "KLineSubCalculate.h"
24 | #import "KLineSocketDataRefersh.h"
25 | #import "UIColor+Extension.h"
26 | #import "UIView+Extension.h"
27 | #import "UIBezierPath+Extension.h"
28 | #define ContentOffSet @"contentOffset"
29 |
30 | #define IsDictionaryNull(dict) (nil == dict || ![dict isKindOfClass:[NSDictionary class]]\
31 | || [dict isKindOfClass:[NSNull class]] || [dict allKeys].count <= 0)
32 | #define IsArrayNull(array) ((nil == array || ![array isKindOfClass:[NSArray class]]\
33 | || [array isKindOfClass:[NSNull class]] || array.count <= 0))
34 | #define IsStringNull(string) (nil == string || [string isKindOfClass:[NSNull class]] \
35 | || string.length <= 0)
36 | #define IsObjectNull(object) (nil == object || [object isKindOfClass:[NSNull class]])
37 |
38 | #define WS(weakSelf) __weak __typeof(&*self)weakSelf = self;
39 |
40 | #define SCREENHEIGHT [UIScreen mainScreen].bounds.size.height
41 | #define SCREENWIDTH [UIScreen mainScreen].bounds.size.width
42 |
43 | #define widthradio SCREENWIDTH/375
44 | #define heightradio SCREENHEIGHT/667
45 |
46 | #define midDistance 40
47 | #define topDistance 10
48 | #define leftDistance 10
49 | #define rightDistance 10
50 | #define bottomDistance 10
51 |
52 | #define timeheight 15
53 |
54 | #define MinCount 10
55 | #define MaxCount 30
56 |
57 | #define KlineCount 88
58 |
59 | #define maxCandelWith 20
60 |
61 | #define minCandelWith 4
62 |
63 | #define ChartViewHigh 400
64 |
65 | #define LandscapeChartViewHigh 300
66 |
67 | #define orignScale 1.0
68 | #define orignChartScale 3.0f/2.0f
69 | #define orignIndicatorScale 1.0f / 3.0f
70 | #define orignIndicatorOrignY 2.0f * orignIndicatorScale
71 |
72 | #define priceWidth 60
73 |
74 | #define RISECOLOR [UIColor colorWithHexString:@"#fb463e"]
75 | #define DROPCOLOR [UIColor colorWithHexString:@"#30b840"]
76 | #define Orientation [[UIApplication sharedApplication] statusBarOrientation]
77 | #define Portrait (Orientation==UIDeviceOrientationPortrait||Orientation==UIDeviceOrientationPortraitUpsideDown)
78 | #define LandscapeLeft (Orientation == UIDeviceOrientationLandscapeLeft)
79 | #define TotalWidth (Portrait ? (PortraitTotalWidth) : (LanscapeTotalWidth))
80 |
81 | #define PortraitTotalWidth KSCREEN_WIDTH
82 | #define LanscapeTotalWidth KSCREEN_HEIGHT
83 | #define KSCREEN_WIDTH MIN([UIScreen mainScreen].bounds.size.width,[UIScreen mainScreen].bounds.size.height)
84 | #define KSCREEN_HEIGHT MAX([UIScreen mainScreen].bounds.size.width,[UIScreen mainScreen].bounds.size.height)
85 |
86 | typedef enum
87 | {
88 | MACD = 1,
89 | KDJ,
90 | WR
91 | }DataLineType;
92 |
93 | typedef NS_ENUM(NSUInteger, ColumnWidthType) {
94 | ColumnWidthTypeEqualCandle = 0,
95 | ColumnWidthTypeEqualLine,
96 | };
97 |
98 | typedef NS_ENUM(NSUInteger, KlineWireSubOrMain) {
99 | Main = 0,
100 | Sub,
101 | };
102 |
103 | typedef NS_ENUM(NSUInteger, WIRETYPE) {
104 | MA5TYPE = 0,
105 | MA10TYPE,
106 | MA20TYPE,
107 | MACDDIFF,
108 | MACDDEA,
109 | KDJ_K,
110 | KDJ_D,
111 | KDJ_J,
112 | KLINE_WR,
113 | };
114 |
115 | typedef NS_ENUM(NSInteger, KlineSubKPIType) {
116 | KlineSubKPITypeATR = 0,
117 | KlineSubKPITypeBIAS = 1,
118 | KlineSubKPITypeCCI = 2,
119 | KlineSubKPITypeKD = 3,
120 | KlineSubKPITypeMACD = 4,
121 | KlineSubKPITypeRSI = 5,
122 | KlineSubKPITypeW_R = 6,
123 | KlineSubKPITypeARBR = 7,
124 | KlineSubKPITypeDKBY = 8,
125 | KlineSubKPITypeKDJ = 9,
126 | KlineSubKPITypeLW_R = 10,
127 | KlineSubKPITypeQHLSR = 11,
128 | KlineSubKPITypeKD5 = 12,
129 | KlineSubKPITypeMACD24 = 13,
130 | };
131 |
132 | #endif
133 |
134 | #endif /* PrefixHeader_h */
135 |
--------------------------------------------------------------------------------
/AbuKlineView/Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix.pch
3 | // AbuKlineView
4 | //
5 | // Created by Jefferson.zhang on 2017/9/6.
6 | // Copyright © 2017年 阿布. All rights reserved.
7 | //
8 |
9 | #ifndef Prefix_h
10 | #define Prefix_h
11 |
12 | #ifdef __OBJC__
13 |
14 | #import
15 | #import
16 |
17 | #import "KlineTitleView.h"
18 | #import "AbuCharViewProtocol.h"
19 | #import "AbuKlineView.h"
20 |
21 |
22 | /** ********************数据模型******************** */
23 | #import "KLineModel.h"
24 |
25 |
26 |
27 | /** ********************单例******************** */
28 | #import "KLineCalculate.h"
29 | #import "KLineSubCalculate.h"
30 |
31 | /** ********************扩展类******************** */
32 | #import "UIColor+Extension.h"
33 | #import "UIView+Extension.h"
34 | #import "UIBezierPath+Extension.h"
35 |
36 |
37 | /** ********************宏定义******************** */
38 |
39 | #define ContentOffSet @"contentOffset"
40 |
41 |
42 | #define IsDictionaryNull(dict) (nil == dict || ![dict isKindOfClass:[NSDictionary class]]\
43 | || [dict isKindOfClass:[NSNull class]] || [dict allKeys].count <= 0)
44 | #define IsArrayNull(array) ((nil == array || ![array isKindOfClass:[NSArray class]]\
45 | || [array isKindOfClass:[NSNull class]] || array.count <= 0))
46 | #define IsStringNull(string) (nil == string || [string isKindOfClass:[NSNull class]] \
47 | || string.length <= 0)
48 | #define IsObjectNull(object) (nil == object || [object isKindOfClass:[NSNull class]])
49 |
50 | #define WS(weakSelf) __weak __typeof(&*self)weakSelf = self;
51 |
52 | #define SCREENHEIGHT [UIScreen mainScreen].bounds.size.height
53 | #define SCREENWIDTH [UIScreen mainScreen].bounds.size.width
54 |
55 | #define widthradio SCREENWIDTH/375
56 | #define heightradio SCREENHEIGHT/667
57 |
58 | #define midDistance 40
59 | #define topDistance 10
60 | #define leftDistance 10
61 | #define rightDistance 10
62 | #define bottomDistance 10
63 |
64 | #define timeheight 15
65 |
66 | #define MinCount 10
67 | #define MaxCount 30
68 |
69 | #define KlineCount 88
70 |
71 | #define maxCandelWith 20
72 |
73 | #define minCandelWith 4
74 |
75 | #define ChartViewHigh 400
76 |
77 | #define LandscapeChartViewHigh 300
78 |
79 | #define orignScale 1.0
80 | #define orignChartScale 3.0f/2.0f
81 | #define orignIndicatorScale 1.0f / 3.0f
82 | #define orignIndicatorOrignY 2.0f * orignIndicatorScale
83 |
84 | #define priceWidth 60
85 |
86 | #define RISECOLOR [UIColor colorWithHexString:@"#fb463e"]
87 |
88 | #define DROPCOLOR [UIColor colorWithHexString:@"#30b840"]
89 |
90 | #define Orientation [[UIApplication sharedApplication] statusBarOrientation]
91 |
92 | #define Portrait (Orientation==UIDeviceOrientationPortrait||Orientation==UIDeviceOrientationPortraitUpsideDown)
93 | #define LandscapeLeft (Orientation == UIDeviceOrientationLandscapeLeft)
94 |
95 | #define TotalWidth (Portrait ? (PortraitTotalWidth) : (LanscapeTotalWidth))
96 |
97 | #define PortraitTotalWidth KSCREEN_WIDTH
98 | #define LanscapeTotalWidth KSCREEN_HEIGHT
99 |
100 | #define KSCREEN_WIDTH MIN([UIScreen mainScreen].bounds.size.width,[UIScreen mainScreen].bounds.size.height)
101 | #define KSCREEN_HEIGHT MAX([UIScreen mainScreen].bounds.size.width,[UIScreen mainScreen].bounds.size.height)
102 |
103 | typedef enum
104 | {
105 | MACD = 1,
106 | KDJ,
107 | WR
108 | }DataLineType;
109 |
110 | /**
111 | * 线状柱或者柱状柱
112 | */
113 | typedef NS_ENUM(NSUInteger, ColumnWidthType) {
114 | ColumnWidthTypeEqualCandle = 0,
115 | ColumnWidthTypeEqualLine,
116 | };
117 |
118 | /**
119 | * 主图或副图
120 | */
121 | typedef NS_ENUM(NSUInteger, KlineWireSubOrMain) {
122 | Main = 0,
123 | Sub,
124 | };
125 |
126 | /**
127 | * 线状类型
128 | */
129 | typedef NS_ENUM(NSUInteger, WIRETYPE) {
130 | MA5TYPE = 0,
131 | MA10TYPE,
132 | MA20TYPE,
133 | MACDDIFF,
134 | MACDDEA,
135 | KDJ_K,
136 | KDJ_D,
137 | KDJ_J,
138 | KLINE_WR,
139 | };
140 |
141 | typedef NS_ENUM(NSInteger, KlineSubKPIType) {
142 | KlineSubKPITypeATR = 0,
143 | KlineSubKPITypeBIAS = 1,
144 | KlineSubKPITypeCCI = 2,
145 | KlineSubKPITypeKD = 3,
146 | KlineSubKPITypeMACD = 4,
147 | KlineSubKPITypeRSI = 5,
148 | KlineSubKPITypeW_R = 6,
149 | KlineSubKPITypeARBR = 7,
150 | KlineSubKPITypeDKBY = 8,
151 | KlineSubKPITypeKDJ = 9,
152 | KlineSubKPITypeLW_R = 10, ///< _ -> &
153 | KlineSubKPITypeQHLSR = 11,
154 | KlineSubKPITypeKD5 = 12,
155 | KlineSubKPITypeMACD24 = 13,
156 | };
157 |
158 | #endif
159 |
160 | #endif /* Prefix_h */
161 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KLineLayer/KlineMALayer.m:
--------------------------------------------------------------------------------
1 | //
2 | // KlineMALayer.m
3 | // ABuKLineChartView
4 | //
5 | // Created by jefferson on 2018/9/7.
6 | // Copyright © 2018年 jefferson. All rights reserved.
7 | //
8 |
9 | #import "KlineMALayer.h"
10 |
11 | @interface KlineMALayer()
12 | @property (nonatomic, strong) NSArray * klineDataSource;
13 | @property (nonatomic,assign) double heightPerpoint;
14 | @property (nonatomic,assign) CGFloat candleWidth;
15 | @property (nonatomic,assign) CGFloat candleSpace;
16 | @property (nonatomic,assign) CGFloat startIndex;
17 | @property (nonatomic,assign) CGFloat maxValue;
18 | @property (nonatomic,strong) UIColor * color;
19 | @property (nonatomic,assign) CGFloat totalHeight;
20 | @property (nonatomic,assign) double lineWidth;
21 | @property (nonatomic,assign) WIRETYPE wiretype;
22 | @property (nonatomic,assign) KlineWireSubOrMain klineWiretype;
23 | @end
24 |
25 | @implementation KlineMALayer
26 |
27 | - (instancetype)initQuotaDataArr:(NSArray *)dataArr candleWidth:(CGFloat)candleWidth candleSpace:(CGFloat)candleSpace startIndex:(CGFloat)startIndex maxValue:(CGFloat)maxValue heightPerpoint:(CGFloat)heightPerpoint totalHeight:(CGFloat)totalHeight lineWidth:(CGFloat)lineWidth lineColor:(UIColor *)lineColor wireType:(WIRETYPE)wiretype klineSubOrMain:(KlineWireSubOrMain)klineWiretype
28 | {
29 | self = [super init];
30 | if (self) {
31 | self.klineDataSource = dataArr;
32 | self.candleWidth = candleWidth;
33 | self.candleSpace = candleSpace;
34 | self.startIndex = startIndex;
35 | self.maxValue = maxValue;
36 | self.heightPerpoint = heightPerpoint;
37 | self.totalHeight = totalHeight;
38 | self.lineWidth = lineWidth;
39 | self.color = lineColor;
40 | self.wiretype = wiretype;
41 | self.klineWiretype = klineWiretype;
42 | [self drawWireLine:[self coverPostionModel]];
43 | }
44 | return self;
45 | }
46 |
47 | - (NSMutableArray *)coverPostionModel
48 | {
49 | NSMutableArray * postions = [NSMutableArray array];
50 | for (int i = 0; i< self.klineDataSource.count; i++) {
51 | KLineModel *model = self.klineDataSource[i];
52 | NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
53 | CGPoint postionPoint;
54 | NSNumber * value = @0.0;
55 | CGFloat yPosition = 0.0;
56 | if (self.wiretype == MA5TYPE) {
57 | value = model.MA5;
58 | }
59 | if (self.wiretype == MA10TYPE)
60 | {
61 | value = model.MA10;
62 | }
63 | if (self.wiretype == MA20TYPE)
64 | {
65 | value = model.MA20;
66 | }
67 | if (self.wiretype == MACDDIFF) {
68 | value = model.DIF;
69 | }
70 | if (self.wiretype == MACDDEA) {
71 | value = model.DEA;
72 | }
73 | if (self.wiretype == KDJ_K) {
74 | if (model.K > 0) {
75 | value = @(model.K);
76 | }
77 | }
78 | if (self.wiretype == KDJ_D) {
79 | if (model.D > 0) {
80 | value = @(model.D);
81 | }
82 | }
83 | if (self.wiretype == KLINE_WR) {
84 | value = @(model.WR);
85 | }
86 | if (!IsObjectNull(value)) {
87 | CGFloat xPosition = self.startIndex + ((self.candleWidth + self.candleSpace) * i) + self.candleWidth/2;
88 | if (self.klineWiretype == Main) {
89 | yPosition = ((self.maxValue - [value floatValue]) * self.heightPerpoint) + topDistance;
90 | }
91 | else if (self.klineWiretype == Sub)
92 | {
93 | yPosition = ABS((self.maxValue - [value floatValue])/self.heightPerpoint) + self.totalHeight + midDistance;
94 | }
95 |
96 | postionPoint = CGPointMake(xPosition, yPosition);
97 | [dictionary setValue:[NSString stringWithFormat:@"%f",postionPoint.x] forKey:@"x"];
98 | [dictionary setValue:[NSString stringWithFormat:@"%f",postionPoint.y] forKey:@"y"];
99 | [postions addObject:dictionary];
100 | }
101 | }
102 | return postions;
103 | }
104 |
105 | - (void)drawWireLine:(NSMutableArray *)postions
106 | {
107 | UIBezierPath * path = [UIBezierPath drawWireLine:postions];
108 | self.path = path.CGPath;
109 | struct CGColor *strokeColor = nil;
110 | strokeColor = self.color.CGColor;
111 | self.strokeColor = strokeColor;
112 | self.fillColor = [UIColor clearColor].CGColor;
113 | }
114 |
115 | @end
116 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KlineCommonView/KlineVerticalView.m:
--------------------------------------------------------------------------------
1 | //
2 | // KlineVerticalView.m
3 | // ABuKLineChartView
4 | //
5 | // Created by jefferson on 2018/9/14.
6 | // Copyright © 2018年 jefferson. All rights reserved.
7 | //
8 |
9 | #import "KlineVerticalView.h"
10 |
11 | #define timeLableheight 20
12 |
13 | @interface KlineVerticalView()
14 |
15 | @property (nonatomic,assign) UIInterfaceOrientation orientation;
16 |
17 | @property (nonatomic,strong) UILabel * timeLabel;
18 |
19 | @property (nonatomic,strong) CAShapeLayer * vereticalLineLayer;
20 |
21 | @end
22 |
23 | @implementation KlineVerticalView
24 |
25 | - (instancetype)init
26 | {
27 | self = [super init];
28 | if (self) {
29 | [self buildUI];
30 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarOrientationChange:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
31 | }
32 | return self;
33 | }
34 |
35 | - (void)buildUI
36 | {
37 | [self buildVerticalLineWithCandleHeight:self.candleChartHeight];
38 | [self addSubview:self.timeLabel];
39 | [self.timeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
40 | make.top.mas_equalTo(self).offset(self.candleChartHeight+(timeLableheight-14)/2);
41 | make.height.mas_equalTo(14);
42 | make.centerX.mas_equalTo(self);
43 | }];
44 | self.timeLabel.text = @"00:00";
45 | }
46 |
47 | - (void)buildVerticalLineWithCandleHeight:(CGFloat)candleChartHeight
48 | {
49 | [self.vereticalLineLayer removeFromSuperlayer];
50 | self.vereticalLineLayer = nil;
51 | self.vereticalLineLayer = [CAShapeLayer layer];
52 | UIBezierPath *topLine = [UIBezierPath bezierPath];
53 | [topLine moveToPoint:CGPointMake(0,0)];
54 | [topLine addLineToPoint:CGPointMake(0,candleChartHeight)];
55 | self.vereticalLineLayer.lineWidth = 1;
56 | self.vereticalLineLayer.path = topLine.CGPath;
57 | self.vereticalLineLayer.lineDashPattern = @[@4, @4];
58 | self.vereticalLineLayer.strokeColor = [UIColor orangeColor].CGColor;
59 | [self.layer addSublayer:self.vereticalLineLayer];
60 | }
61 |
62 | #pragma mark - PublicMethods
63 | - (void)updateTimeString:(NSString *)timeString
64 | {
65 | NSLog(@"%@",timeString);
66 | self.timeLabel.text = timeString;
67 | }
68 |
69 | - (void)updateTimeLeft:(CGFloat)leftdistance
70 | {
71 | [self.timeLabel mas_updateConstraints:^(MASConstraintMaker *make) {
72 | make.centerX.equalTo(self).offset(leftdistance);
73 | }];
74 | }
75 |
76 | - (void)updateHeight:(CGFloat)candleChartHeight
77 | {
78 | [self.timeLabel mas_updateConstraints:^(MASConstraintMaker *make) {
79 |
80 | make.top.mas_equalTo(self).offset(candleChartHeight+(timeLableheight-14)/2);
81 | }];
82 | [self buildVerticalLineWithCandleHeight:candleChartHeight];
83 | }
84 | - (void)statusBarOrientationChange:(NSNotification *)notification
85 | {
86 |
87 | self.orientation = [[UIApplication sharedApplication] statusBarOrientation];
88 |
89 | if (self.orientation == UIDeviceOrientationPortrait || self.orientation == UIDeviceOrientationPortraitUpsideDown) {
90 |
91 | [self.timeLabel mas_updateConstraints:^(MASConstraintMaker *make) {
92 |
93 | make.top.mas_equalTo(self).offset(self.candleChartHeight+(timeLableheight-14)/2);
94 | }];
95 | [self buildVerticalLineWithCandleHeight:self.candleChartHeight];
96 | }
97 | if (self.orientation==UIDeviceOrientationLandscapeLeft || self.orientation == UIDeviceOrientationLandscapeRight) {
98 |
99 | [self.timeLabel mas_updateConstraints:^(MASConstraintMaker *make) {
100 |
101 | make.top.mas_equalTo(self).offset(self.candleChartHeight+(timeLableheight-14)/2);
102 | }];
103 | [self buildVerticalLineWithCandleHeight:self.candleChartHeight];
104 | }
105 | }
106 |
107 | - (UILabel *)timeLabel
108 | {
109 | if (!_timeLabel) {
110 | _timeLabel = [[UILabel alloc] init];
111 | _timeLabel.font = [UIFont systemFontOfSize:9];
112 | _timeLabel.textColor = [UIColor whiteColor];
113 | _timeLabel.backgroundColor = [UIColor colorWithHexString:@"#608fd8"];
114 | }
115 | return _timeLabel;
116 | }
117 | - (UIInterfaceOrientation)orientation
118 | {
119 | return [[UIApplication sharedApplication] statusBarOrientation];
120 | }
121 | - (CGFloat)candleChartHeight
122 | {
123 | CGFloat HEIGH = 0;
124 | if (self.orientation == UIDeviceOrientationPortrait || self.orientation == UIDeviceOrientationPortraitUpsideDown) {
125 |
126 | HEIGH = ChartViewHigh - 20;
127 | }
128 | if (self.orientation==UIDeviceOrientationLandscapeLeft || self.orientation == UIDeviceOrientationLandscapeRight) {
129 |
130 | HEIGH = LandscapeChartViewHigh - 20;
131 | }
132 | return HEIGH;
133 | }
134 |
135 | -(void)dealloc
136 | {
137 | [[NSNotificationCenter defaultCenter] removeObserver:self];
138 | }
139 |
140 | @end
141 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KLineTitleView/KlineTitleView.m:
--------------------------------------------------------------------------------
1 | //
2 | // KlineTitleView.m
3 | // LGTS2
4 | //
5 | // Created by Jefferson.zhang on 2017/7/18.
6 | // Copyright © 2017年 Mata. All rights reserved.
7 | //
8 |
9 | #import "KlineTitleView.h"
10 |
11 | #define kHeight [UIScreen mainScreen].bounds.size.height
12 | #define lineWidth 30.0f
13 | #define lineHight 3.0f
14 |
15 | @interface KlineTitleView()
16 | @property (nonatomic, strong) UIView * line;
17 |
18 | @property (nonatomic, strong) UIView * titleView;
19 |
20 | @property (nonatomic, assign) NSInteger selectIndex;
21 |
22 | @property (nonatomic, strong) NSArray * titleArray;
23 |
24 | @property (nonatomic, strong) NSArray * typeArray;
25 |
26 | @property (nonatomic, assign) NSInteger count;
27 |
28 | @end
29 |
30 |
31 | @implementation KlineTitleView
32 |
33 | - (instancetype)initWithklineTitleArray:(NSArray *)titleArray typeArray:(NSArray *)typeArray
34 | {
35 | self = [super init];
36 | if (self) {
37 | self.selectIndex = 0;
38 | self.titleArray = titleArray;
39 | self.typeArray = typeArray;
40 | self.count = typeArray.count;
41 | [self buildTitleView];
42 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarOrientationChange:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
43 | }
44 | return self;
45 | }
46 |
47 | - (void)statusBarOrientationChange:(NSNotification *)notification
48 | {
49 | NSInteger inde = self.selectIndex;
50 | for (UIView * view in self.titleView.subviews) {
51 | if ([view isKindOfClass:[UIButton class]]) {
52 | [view removeFromSuperview];
53 | }
54 | }
55 |
56 | if (self.orientation == UIDeviceOrientationPortrait || self.orientation == UIDeviceOrientationPortraitUpsideDown) {
57 | self.titleView.frame = CGRectMake(0, 0, TotalWidth, 33);
58 | [self buildTitleButton];
59 | }else if (self.orientation==UIDeviceOrientationLandscapeLeft || self.orientation == UIDeviceOrientationLandscapeRight) {
60 | self.titleView.frame = CGRectMake(0, 0, TotalWidth, 33);
61 | self.count = self.typeArray.count;
62 | [self buildTitleButton];
63 | }
64 |
65 | [self changeLineFrame:inde];
66 | }
67 |
68 | - (void)buildTitleView
69 | {
70 | [self addConstrains];
71 | [self addSubview:self.titleView];
72 | [self.titleView addSubview:self.line];
73 | }
74 |
75 | - (void)addConstrains
76 | {
77 | if (self.orientation == UIDeviceOrientationPortrait || self.orientation == UIDeviceOrientationPortraitUpsideDown) {
78 | self.titleView.frame = CGRectMake(0, 0, TotalWidth, 33);
79 | [self buildTitleButton];
80 |
81 |
82 | }else if (self.orientation==UIDeviceOrientationLandscapeLeft || self.orientation == UIDeviceOrientationLandscapeRight) {
83 | self.titleView.frame = CGRectMake(0, 0, TotalWidth, 33);
84 | [self buildTitleButton];
85 | }
86 | }
87 |
88 | - (void)buildTitleButton
89 | {
90 | for (NSInteger i = 0; i < self.typeArray.count; i++) {
91 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
92 | button.frame = CGRectMake(TotalWidth / self.count * i, 0, TotalWidth / self.count, 30);
93 | [button setTitle:_titleArray[i] forState:UIControlStateNormal];
94 | if (i == self.selectIndex) {
95 | button.selected = YES;
96 | }
97 | [button setTitleColor:[UIColor colorWithHexString:@"#608fdb"] forState:UIControlStateSelected];
98 | [button setTitleColor:[UIColor colorWithHexString:@"#7b8396"] forState:UIControlStateNormal];
99 | button.titleLabel.font = [UIFont systemFontOfSize:12];
100 | button.titleLabel.textAlignment = NSTextAlignmentCenter;
101 | button.userInteractionEnabled = YES;
102 | [button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
103 | button.tag = [self.typeArray[i] integerValue];
104 | [self.titleView addSubview:button];
105 | }
106 | }
107 |
108 | - (void)buttonAction:(UIButton *)btn
109 | {
110 | KLINETYPE type = (KLINETYPE)btn.tag;
111 | for (int i = 0; i < self.typeArray.count; i++) {
112 | if (btn.tag == [self.typeArray[i] integerValue]) {
113 | self.selectIndex = i;
114 | }
115 | }
116 | for (UIButton *bt in self.titleView.subviews) {
117 | if ([bt isKindOfClass:[UIButton class]]) {
118 | bt.selected = NO;
119 | if (self.selectIndex
10 |
11 | @interface KLineModel : NSObject
12 |
13 | /** 最高价 */
14 | @property (assign, nonatomic) CGFloat highPrice;
15 | /** 最低价 */
16 | @property (assign, nonatomic) CGFloat lowPrice;
17 | /** 开盘价 */
18 | @property (assign, nonatomic) CGFloat openPrice;
19 | /** 收盘价 */
20 | @property (assign, nonatomic) CGFloat closePrice;
21 | /** 日期 */
22 | @property (copy, nonatomic) NSString * date;
23 | /** 成交量 */
24 | @property (copy, nonatomic) NSString * volumn;
25 | /** 是否需要绘制日期 */
26 | @property (assign, nonatomic) BOOL isDrawDate;
27 |
28 | @property (nonatomic,assign) double currentPrice;
29 | @property (nonatomic,assign) NSInteger timestamp;
30 |
31 |
32 | @property (nonatomic,assign) BOOL isNew;
33 |
34 |
35 | //model中应该最后处理成坐标数据
36 | @property (nonatomic,copy) NSString *timeStr;
37 |
38 | @property (nonatomic,assign) NSUInteger xPoint;
39 | /**
40 | *蜡烛矩形起点
41 | */
42 | @property (nonatomic,assign) CGFloat y;
43 | /**
44 | *蜡烛矩形高度
45 | */
46 | @property (nonatomic,assign) CGFloat h;
47 | /**
48 | *蜡烛开盘点
49 | */
50 | @property (nonatomic,assign) CGPoint opensPoint;
51 | /**
52 | *蜡烛收盘点
53 | */
54 | @property (nonatomic,assign) CGPoint closesPoint;
55 | /**
56 | *蜡烛最高点
57 | */
58 | @property (nonatomic,assign) CGPoint highestPoint;
59 | /**
60 | *蜡烛最低点
61 | */
62 | @property (nonatomic,assign) CGPoint lowestPoint;
63 | /**
64 | *填充颜色
65 | */
66 | @property (nonatomic,strong) UIColor *fillColor;
67 | /**
68 | *边线绘制颜色
69 | */
70 | @property (nonatomic,strong) UIColor *strokeColor;
71 | /**
72 | *判断是否是NSTimer推送的数据
73 | */
74 | @property (nonatomic,assign) BOOL isFakeData;
75 | /**
76 | *当数据不足以显示一屏的时候的判断处理
77 | */
78 | @property (nonatomic,assign) BOOL isPlaceHolder;
79 |
80 |
81 |
82 |
83 | //MACD
84 | //这里由于是使用懒加载的,所以必须声明为对象类型才能保存在模型中
85 | //previousKlineModel
86 | @property (nonatomic,strong) KLineModel *previousKlineModel;
87 | @property (nonatomic,strong) NSNumber *EMA12;
88 | @property (nonatomic,strong) NSNumber *EMA26;
89 | @property (nonatomic,strong) NSNumber *DIF;
90 | @property (nonatomic,strong) NSNumber *DEA;
91 | @property (nonatomic,strong) NSNumber *MACD;
92 | - (void)reInitData;
93 |
94 |
95 |
96 |
97 | //KDJ
98 | //KDJ(9,3.3),下面以该参数为例说明计算方法。
99 | //9,3,3代表指标分析周期为9天,K值D值为3天
100 | //RSV(9)=(今日收盘价-9日内最低价)÷(9日内最高价-9日内最低价)×100
101 | //K(3日)=(当日RSV值+2*前一日K值)÷3
102 | //D(3日)=(当日K值+2*前一日D值)÷3
103 | //J=3K-2D
104 | @property (nonatomic,strong) NSNumber *HNinePrice;
105 | @property (nonatomic,strong) NSNumber *LNinePrice;
106 | @property (nonatomic, copy) NSNumber *RSV_9;
107 | @property (nonatomic, copy) NSNumber *KDJ_K;
108 | @property (nonatomic, copy) NSNumber *KDJ_D;
109 | @property (nonatomic, copy) NSNumber *KDJ_J;
110 | - (void)reInitKDJData;
111 |
112 |
113 | //BOLL
114 | /*
115 | 20日BOLL指标的计算过程
116 | (1)计算MA
117 | MA=N日内的收盘价之和÷N
118 | (2)计算标准差MD
119 | MD=平方根(N日的(C-MA)的两次方之和除以N)
120 | (3)计算MB、UP、DN线
121 | MB=(N-1)日的MA
122 | UP=MB+2×MD
123 | DN=MB-2×MD
124 | 在股市分析软件中,BOLL指标一共由四条线组成,即上轨线UP 、中轨线MB、下轨线DN和价格线。其中上轨线UP是UP数值的连线,用黄色线表示;中轨线MB是MB数值的连线,用白色线表示;下轨线DN是DN数值的连线,用紫色线表示;价格线是以美国线表示,颜色为浅蓝色。和其他技术指标一样,在实战中,投资者不需要进行BOLL指标的计算,主要是了解BOLL的计算方法和过程,以便更加深入地掌握BOLL指标的实质,为运用指标打下基础。
125 |
126 | */
127 | @property (nonatomic, copy) NSNumber *BOLL_MA;
128 | @property (nonatomic, copy) NSNumber *BOLL_MD;
129 | @property (nonatomic, copy) NSNumber *BOLL_MB;
130 | @property (nonatomic, copy) NSNumber *BOLL_UP;
131 | @property (nonatomic, copy) NSNumber *BOLL_DN;
132 |
133 | - (void)reInitBOLLData;
134 |
135 |
136 |
137 |
138 | //RSI
139 | /*
140 | RSI的计算公式
141 | RSI=100×RS/(1+RS) 或者,RSI=100-100÷(1+RS)
142 | 其中 RS=14天内收市价上涨数之和的平均值/14天内收市价下跌数之和的平均值
143 | 举例说明:
144 | 如果最近14天涨跌情形是:第一天升2元,第二天跌2元,第三至第五天各升3元;第六天跌4元 第七天升2元,第八天跌5元;第九天跌6元,第十至十二天各升1元;第十三至十四天各跌3元。
145 | 那么,计算RSI的步骤如下:
146 | (一)将14天上升的数目相加,除以14,上例中总共上升16元除以14得1.143(精确到小数点后三位);
147 | (二)将14天下跌的数目相加,除以14,上例中总共下跌23元除以14得1.643(精确到小数点后三位);
148 | (三)求出相对强度RS,即RS=1.143/1.643=0.696(精确到小数点后三位);
149 | (四)1+RS=1+0.696=1.696;
150 | (五)以100除以1+RS,即100/1.696=58.962;
151 | (六)100-58.962=41.038。 结果14天的强弱指标RS1为41.038。 不同日期的14天RSI值当然是不同的,连接不同的点,即成RSI的轨迹。
152 |
153 | */
154 |
155 | @property (nonatomic, copy) NSNumber *RSI_6;
156 | @property (nonatomic, copy) NSNumber *RSI_12;
157 | @property (nonatomic, copy) NSNumber *RSI_14;
158 | @property (nonatomic, copy) NSNumber *RSI_21;
159 | @property (nonatomic, copy) NSNumber *RSI_24;
160 | @property (nonatomic, assign)double SMAMAX;
161 | @property (nonatomic, assign)double SMAABS;
162 | - (void)judgeRSIIsNan;
163 |
164 | //CGFloat UPDM = 0;
165 | //CGFloat DNDM = 0;
166 | //CGFloat TR = 0;
167 | //CGFloat SUNMDX = 0;
168 | //CGFloat ADMUP = 0;
169 | //CGFloat ADMDN = 0;
170 | //CGFloat ATR = 0;
171 | //CGFloat DIUP = 0;
172 | //CGFloat DIDN = 0;
173 | //CGFloat DX = 0;
174 | @property (nonatomic, assign)double UPDM;
175 | @property (nonatomic, assign)double DNDM;
176 | @property (nonatomic, assign)double ADXTR;
177 | @property (nonatomic, assign)double ADMUP;
178 | @property (nonatomic, assign)double ADMDN;
179 | @property (nonatomic, assign)double ADXATR;
180 | @property (nonatomic, assign)double DIUP;
181 | @property (nonatomic, assign)double DIDN;
182 | @property (nonatomic, assign)double DX;
183 | @property (nonatomic, assign)double ADX;
184 |
185 | //VOL
186 | @property (nonatomic, copy) NSNumber *volumn_MA5;
187 | @property (nonatomic, copy) NSNumber *volumn_MA10;
188 | @property (nonatomic, copy) NSNumber *volumn_MA20;
189 |
190 |
191 |
192 | //MA
193 | @property (nonatomic, copy) NSNumber *MA5;
194 | @property (nonatomic, copy) NSNumber *MA10;
195 | @property (nonatomic, copy) NSNumber *MA14;
196 | @property (nonatomic, copy) NSNumber *MA20;
197 |
198 | //ARBP
199 | @property (nonatomic, assign) NSInteger N;
200 | @property (nonatomic, copy) NSNumber * AR;
201 | @property (nonatomic, copy) NSNumber * BR;
202 | - (void)reInitARBPData;
203 |
204 | //ATR
205 | @property (nonatomic, assign) double TR;
206 | @property (nonatomic, assign) double ATR;
207 |
208 | //BIAS
209 | @property (nonatomic, assign) double BIAS1;
210 | @property (nonatomic, assign) double BIAS2;
211 | @property (nonatomic, assign) double BIAS3;
212 | - (void)reInitBIASData;
213 |
214 | //CCI
215 | @property (nonatomic, assign) double TP;
216 | @property (nonatomic, assign) double CCI;
217 |
218 | //DKBY
219 | @property (nonatomic, assign) double SMA;
220 |
221 | @property (nonatomic, assign) double SELL;
222 | @property (nonatomic, assign) double BUY;
223 | @property (nonatomic, assign) double ENE1;
224 | @property (nonatomic, assign) double ENE2;
225 |
226 | //KD
227 | @property (nonatomic, assign) double RSV;
228 | @property (nonatomic, assign) double K;
229 | @property (nonatomic, assign) double D;
230 |
231 |
232 | //LWR
233 | @property (nonatomic, assign) double LWR1;
234 | @property (nonatomic, assign) double LWR2;
235 |
236 | //WR
237 | @property (nonatomic, assign) double WR;
238 |
239 | //QHLSR
240 | @property (nonatomic, assign) double DD;
241 | @property (nonatomic, assign) double GG;
242 |
243 | @property (nonatomic, assign) double EMA1;
244 | @property (nonatomic, assign) double EMA2;
245 | @property (nonatomic, assign) double EMA3;
246 | @property (nonatomic, assign) double EMA4;
247 | @property (nonatomic, assign) double EMA5;
248 | @property (nonatomic, assign) double EMA6;
249 |
250 | @property (nonatomic, assign) double PBX1;
251 | @property (nonatomic, assign) double PBX2;
252 | @property (nonatomic, assign) double PBX3;
253 | @property (nonatomic, assign) double PBX4;
254 | @property (nonatomic, assign) double PBX5;
255 | @property (nonatomic, assign) double PBX6;
256 |
257 | @end
258 |
--------------------------------------------------------------------------------
/AbuKlineView/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // AbuKlineView
4 | //
5 | // Created by 阿布 on 17/9/6.
6 | // Copyright © 2017年 阿布. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 | #import "AppDelegate.h"
11 | #import "KLineSubCalculate.h"
12 | @interface ViewController ()
13 |
14 | @property (nonatomic, strong) NSString * currentRequestType;
15 |
16 | @property (nonatomic, strong) KlineTitleView * klineTitleView;
17 |
18 | @property (nonatomic, assign) KLINETYPE currentType;
19 |
20 | @property (nonatomic, strong) AbuKlineView * kLineView;
21 |
22 | @property (nonatomic,strong) KLineModel * model;
23 |
24 | @property (nonatomic,strong) NSMutableArray * dataSource;
25 |
26 | @property (nonatomic,assign) UIInterfaceOrientation orientation;
27 |
28 | @end
29 |
30 | @implementation ViewController
31 |
32 | - (void)viewDidAppear:(BOOL)animated
33 | {
34 | [super viewDidAppear:animated];
35 |
36 | ((AppDelegate *)[UIApplication sharedApplication].delegate).allowRotation = YES;
37 |
38 | }
39 |
40 | - (void)viewDidDisappear:(BOOL)animated
41 | {
42 | [super viewDidDisappear:animated];
43 |
44 | ((AppDelegate *)[UIApplication sharedApplication].delegate).allowRotation = NO;
45 | [self supportRotion:UIInterfaceOrientationPortrait];
46 | }
47 |
48 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
49 | {
50 | return YES;
51 | }
52 |
53 | #if __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_9_0
54 | - (NSUInteger)supportedInterfaceOrientations
55 | #else
56 | - (UIInterfaceOrientationMask)supportedInterfaceOrientations
57 | #endif
58 | {
59 | return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationLandscapeLeft;
60 | }
61 |
62 | - (void)viewDidLoad {
63 | [super viewDidLoad];
64 | self.view.backgroundColor = [UIColor blackColor];
65 | self.currentType = K_LINE_1MIN;
66 | [self buildKLineTitleView];
67 | [self.view addSubview:self.kLineView];
68 | [self addKLineSubView];
69 | [self requestKLineViewHistoryListWithType:self.currentType];
70 | }
71 |
72 | - (void)buildKLineTitleView
73 | {
74 | [self.view addSubview:self.klineTitleView];
75 |
76 | }
77 |
78 | - (void)addKLineSubView
79 | {
80 | WS(weakSelf);
81 | self.orientation = [[UIApplication sharedApplication] statusBarOrientation];
82 |
83 | if (self.orientation == UIDeviceOrientationPortrait || self.orientation == UIDeviceOrientationPortraitUpsideDown) {
84 | [self.klineTitleView mas_makeConstraints:^(MASConstraintMaker *make) {
85 | make.left.right.equalTo(weakSelf.view);
86 | make.top.equalTo(weakSelf.view).offset(100);
87 | make.height.mas_offset(30);
88 | }];
89 | [self.kLineView mas_makeConstraints:^(MASConstraintMaker *make) {
90 | make.top.equalTo(weakSelf.view).offset(132);
91 | make.right.equalTo(weakSelf.view.mas_right);
92 | make.left.equalTo(weakSelf.view.mas_left);
93 | make.height.mas_offset(ChartViewHigh);
94 | }];
95 | }
96 | if (self.orientation==UIDeviceOrientationLandscapeLeft || self.orientation == UIDeviceOrientationLandscapeRight) {
97 | [self.klineTitleView mas_makeConstraints:^(MASConstraintMaker *make) {
98 | make.left.right.equalTo(weakSelf.view);
99 | make.top.equalTo(weakSelf.view).offset(40);
100 | make.height.mas_offset(30);
101 | }];
102 | [self.kLineView mas_makeConstraints:^(MASConstraintMaker *make) {
103 | make.top.equalTo(weakSelf.view).offset(72);
104 | make.right.equalTo(weakSelf.view.mas_right);
105 | make.left.equalTo(weakSelf.view.mas_left);
106 | make.height.mas_offset(LandscapeChartViewHigh);
107 | }];
108 | }
109 | }
110 |
111 | - (void)selectIndex:(KLINETYPE)type
112 | {
113 | if (type == self.currentType) {
114 | return;
115 | }
116 | [self requestKLineViewHistoryListWithType:type];
117 | self.currentType = type;
118 | }
119 |
120 |
121 |
122 | - (void)requestKLineViewHistoryListWithType:(KLINETYPE)type
123 | {
124 | if (type == K_LINE_1MIN)
125 | {
126 | [self loadStockDataWithJson:@"stock1"];
127 | self.currentRequestType = @"M1";
128 | }
129 | else if (type == K_LINE_5MIN)
130 | {
131 | [self loadStockDataWithJson:@"stock5"];
132 | self.currentRequestType = @"M5";
133 | }
134 | else if (type == K_LINE_15MIN)
135 | {
136 | [self loadStockDataWithJson:@"stock15"];
137 | self.currentRequestType = @"M15";
138 | }
139 | else if (type == K_LINE_30MIN)
140 | {
141 | [self loadStockDataWithJson:@"stock30"];
142 | self.currentRequestType = @"M30";
143 | }
144 | else if (type == K_LINE_1HOUR || type == K_LINE_60MIN)
145 | {
146 | [self loadStockDataWithJson:@"stock60"];
147 | self.currentRequestType = @"H1";
148 | }
149 | else if (type == K_LINE_DAY)
150 | {
151 | [self loadStockDataWithJson:@"stockDay"];
152 | self.currentRequestType = @"D1";
153 | }
154 | }
155 |
156 | - (void)loadStockDataWithJson:(NSString *)json
157 | {
158 | NSString *Path = [[NSBundle mainBundle] pathForResource:json ofType:@"json"];
159 | NSData *data = [[NSData alloc] initWithContentsOfFile:Path];
160 |
161 | NSDictionary * stockDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
162 | if (IsDictionaryNull(stockDict)) {
163 | return;
164 | }
165 | if (self.dataSource) {
166 | [self.dataSource removeAllObjects];
167 | }
168 | NSArray * stockData = stockDict[@"d"][@"p"];
169 | for (int i = 0; i < stockData.count; i++)
170 | {
171 | NSDictionary * dic = stockData[i];
172 | KLineModel * model = [[KLineModel alloc]init];
173 | model.closePrice = [dic[@"c"] floatValue];
174 | model.openPrice = [dic[@"o"] floatValue];
175 | model.highPrice = [dic[@"h"] floatValue];
176 | model.lowPrice = [dic[@"l"] floatValue];
177 | model.date = [self changeDtaForMatMmDd:dic[@"t"] range:NSMakeRange(14, 2)];
178 | model.timestamp = (NSInteger)[self changeTime:model.date];
179 | model.timeStr = [self updateTime:[NSString stringWithFormat:@"%ld",(long)model.timestamp]];
180 | model.volumn = dic[@"v"];
181 | if (i % 16 == 0)
182 | {
183 | model.isDrawDate = YES;
184 | }
185 | [self.dataSource addObject:model];
186 | }
187 | self.dataSource = [[[KLineSubCalculate sharedInstance] initializeQuotaDataWithArray:self.dataSource KPIType:4] mutableCopy];
188 | dispatch_async(dispatch_get_main_queue(), ^{
189 | self.kLineView.dataArray = self.dataSource;
190 | });
191 | }
192 |
193 | - (NSString *)changeDtaForMatMmDd:(NSString *)data range:(NSRange)range
194 | {
195 | NSArray * timeArray = [data componentsSeparatedByString:@"T"];
196 | NSString * time = [timeArray.firstObject stringByAppendingString:[NSString stringWithFormat:@" %@",timeArray.lastObject]];
197 | return time;
198 | }
199 |
200 | - (long)changeTime:(NSString *)time
201 | {
202 | NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
203 | [formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"];
204 | NSDate *lastDate = [formatter dateFromString:time];
205 | long firstStamp = [lastDate timeIntervalSince1970];
206 | return firstStamp;
207 | }
208 |
209 | -(NSString*)updateTime:(NSString*)time{
210 |
211 | NSString *format = nil;
212 | if ([self.currentRequestType containsString:@"D"]||[self.currentRequestType containsString:@"W"]||[self.currentRequestType isEqualToString:@"MN"]) {
213 | format = @"MM-dd";
214 | }else if ([self.currentRequestType containsString:@"M"]||[self.currentRequestType containsString:@"H"])
215 | {
216 | format = @"MM-dd HH:mm";
217 | }
218 | NSDateFormatter*formatter = [[NSDateFormatter alloc]init];
219 | [formatter setDateStyle:NSDateFormatterMediumStyle];
220 | [formatter setTimeStyle:NSDateFormatterShortStyle];
221 | [formatter setDateFormat:format];
222 | int timeval = [time intValue];
223 | NSDate*confromTimesp = [NSDate dateWithTimeIntervalSince1970:timeval];
224 | NSString *confromTimespStr = [formatter stringFromDate:confromTimesp];
225 | return confromTimespStr;
226 | }
227 |
228 | - (KlineTitleView *)klineTitleView
229 | {
230 | if (!_klineTitleView) {
231 | _klineTitleView = [[KlineTitleView alloc] initWithklineTitleArray:@[@"1分",@"5分",@"15分",@"30分",@"1小时",@"日K"] typeArray:@[@34,@1,@2,@3,@37,@5]];
232 | _klineTitleView.delegate = self;
233 | }
234 | return _klineTitleView;
235 | }
236 |
237 | - (UIInterfaceOrientation)orientation
238 | {
239 | return [[UIApplication sharedApplication] statusBarOrientation];
240 | }
241 |
242 | - (NSMutableArray *)dataSource
243 | {
244 | if (!_dataSource) {
245 | _dataSource = [NSMutableArray array];
246 | }
247 | return _dataSource;
248 | }
249 |
250 | - (AbuKlineView *)kLineView
251 | {
252 | if (!_kLineView) {
253 | _kLineView = [[AbuKlineView alloc]init];
254 | }
255 | return _kLineView;
256 | }
257 |
258 |
259 |
260 |
261 | @end
262 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KLineView/AbuKlineView.m:
--------------------------------------------------------------------------------
1 | //
2 | // AbuKlineView.m
3 | // AbuKlineView
4 | //
5 | // Created by Jefferson.zhang on 2017/9/6.
6 | // Copyright © 2017年 阿布. All rights reserved.
7 | //
8 |
9 | #import "AbuKlineView.h"
10 | #import "AbuCandChartView.h"
11 | #import "KlineCurrentPriceView.h"
12 | #import "KlineVerticalView.h"
13 | #import "KlinePriceView.h"
14 | @interface AbuKlineView()
15 | @property (nonatomic, strong) UIScrollView * scrollView;
16 | @property (nonatomic, strong) AbuCandChartView * candleChartView;
17 | @property (nonatomic, strong) KLineModel * model;
18 | @property (nonatomic,strong) KlinePriceView * priceView;
19 | @property (nonatomic, strong) KlinePriceView * quotaPriceView;
20 | @property (nonatomic, strong) UILongPressGestureRecognizer * longPressGesture;
21 | @property (nonatomic, strong) UIPinchGestureRecognizer * pinchPressGesture;
22 | @property (nonatomic, strong) UITapGestureRecognizer * tapGesture;
23 | @property (nonatomic, strong) KlineVerticalView * verticalView;
24 | @property (nonatomic, strong) KlineCurrentPriceView * leavView;
25 | @property (nonatomic, strong) UILabel * dataLable;
26 | @property (nonatomic, strong) KlineCurrentPriceView * currentPriceView;
27 | @property (nonatomic, assign) NSInteger curentIndex;
28 | @property (nonatomic,assign) UIInterfaceOrientation orientation;
29 | @property (nonatomic, assign) BOOL ishow;
30 | @end
31 |
32 | @implementation AbuKlineView
33 |
34 | - (instancetype)init
35 | {
36 | self = [super init];
37 | if (self) {
38 | [self setUI];
39 | }
40 | return self;
41 | }
42 |
43 | - (instancetype)initWithFrame:(CGRect)frame
44 | {
45 | self = [super initWithFrame:frame];
46 | if (self) {
47 | [self setUI];
48 | }
49 | return self;
50 | }
51 |
52 | - (void)setUI{
53 |
54 | _curentIndex = 0;
55 | self.ishow = YES;
56 | [self addSubview:self.scrollView];
57 | [self initChartView];
58 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarOrientationChange:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
59 | }
60 |
61 | - (void)statusBarOrientationChange:(NSNotification *)notification
62 | {
63 | WS(weakSelf);
64 |
65 | self.orientation = [[UIApplication sharedApplication] statusBarOrientation];
66 | if (self.orientation == UIDeviceOrientationPortrait || self.orientation == UIDeviceOrientationPortraitUpsideDown) {
67 | [self.scrollView mas_updateConstraints:^(MASConstraintMaker *make) {
68 | make.height.mas_offset(ChartViewHigh);
69 | }];
70 | [self.candleChartView mas_updateConstraints:^(MASConstraintMaker *make) {
71 | make.height.mas_offset(ChartViewHigh);
72 | }];
73 | }
74 | if (self.orientation==UIDeviceOrientationLandscapeLeft || self.orientation == UIDeviceOrientationLandscapeRight) {
75 | [self.scrollView mas_updateConstraints:^(MASConstraintMaker *make) {
76 | make.height.mas_offset(LandscapeChartViewHigh);
77 | }];
78 | [self.candleChartView mas_updateConstraints:^(MASConstraintMaker *make) {
79 | make.height.mas_offset(LandscapeChartViewHigh);
80 | }];
81 | }
82 | if (self.ishow) {
83 | [self.priceView mas_remakeConstraints:^(MASConstraintMaker *make) {
84 | make.right.top.equalTo(weakSelf);
85 | make.left.equalTo(weakSelf.scrollView.mas_right);
86 | make.height.mas_equalTo(weakSelf.candleChartView.mas_height).multipliedBy(2.0f / 3.0f);
87 | }];
88 | [self.priceView updateFrameWithHeight:weakSelf.scrollView.height * orignIndicatorOrignY];
89 | }
90 | else
91 | {
92 | [self.priceView mas_remakeConstraints:^(MASConstraintMaker *make) {
93 | make.bottom.right.top.equalTo(weakSelf);
94 | make.left.equalTo(weakSelf.scrollView.mas_right);
95 | }];
96 | [self.priceView updateFrameWithHeight:weakSelf.scrollView.height];
97 | }
98 | }
99 | -(void)initChartView{
100 | [self addSubview:self.priceView];
101 | [self addSubview:self.quotaPriceView];
102 | [self.scrollView addSubview:self.candleChartView];
103 | [self addConstrains];
104 | [self addGesture];
105 | [self initCrossLine];
106 | [self initdataLabel];
107 | [self initCurrentPrice];
108 | }
109 |
110 | - (void)addConstrains
111 | {
112 | WS(weakSelf);
113 |
114 | self.orientation = [[UIApplication sharedApplication] statusBarOrientation];
115 | CGFloat height = 0.0;
116 | if (self.orientation == UIDeviceOrientationPortrait || self.orientation == UIDeviceOrientationPortraitUpsideDown) {
117 | [_scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
118 | make.top.equalTo(weakSelf);
119 | make.left.equalTo(weakSelf);
120 | make.right.equalTo(weakSelf.mas_right).offset(-priceWidth);
121 | make.height.mas_offset(ChartViewHigh);
122 | }];
123 |
124 | [self.candleChartView mas_makeConstraints:^(MASConstraintMaker *make) {
125 | make.top.equalTo(weakSelf);
126 | make.left.equalTo(weakSelf.scrollView.mas_left);
127 | make.right.equalTo(weakSelf).offset(-5);
128 | make.height.mas_offset(ChartViewHigh);
129 | }];
130 | height = ChartViewHigh;
131 | }
132 | if (self.orientation==UIDeviceOrientationLandscapeLeft || self.orientation == UIDeviceOrientationLandscapeRight) {
133 | [_scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
134 | make.top.equalTo(weakSelf);
135 | make.left.equalTo(weakSelf).offset(5);
136 | make.right.equalTo(weakSelf.mas_right).offset(-priceWidth);
137 | make.height.mas_offset(LandscapeChartViewHigh);
138 | }];
139 | [self.candleChartView mas_makeConstraints:^(MASConstraintMaker *make) {
140 | make.top.equalTo(weakSelf);
141 | make.left.equalTo(weakSelf.scrollView.mas_left);
142 | make.right.equalTo(weakSelf).offset(-5);
143 | make.height.mas_offset(LandscapeChartViewHigh);
144 | }];
145 | height = LandscapeChartViewHigh;
146 | }
147 |
148 | [self.priceView mas_makeConstraints:^(MASConstraintMaker *make) {
149 | make.top.equalTo(weakSelf.mas_top);
150 | make.right.equalTo(weakSelf);
151 | make.left.equalTo(weakSelf.scrollView.mas_right);
152 | make.height.mas_equalTo(weakSelf.candleChartView.mas_height).multipliedBy(2.0f / 3.0f);
153 | }];
154 |
155 | [self.quotaPriceView mas_makeConstraints:^(MASConstraintMaker *make) {
156 | make.top.equalTo(weakSelf.priceView.mas_bottom);
157 | make.right.equalTo(weakSelf);
158 | make.left.equalTo(weakSelf.scrollView.mas_right);
159 | make.bottom.equalTo(weakSelf);
160 | }];
161 | [self.priceView updateFrameWithHeight:height * 2.0f / 3.0f];
162 | [self.quotaPriceView updateFrameWithHeight:height * 1.0f / 3.0f];
163 | }
164 | - (void)addGesture
165 | {
166 | _longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longGesture:)];
167 | [self.candleChartView addGestureRecognizer:_longPressGesture];
168 |
169 | _pinchPressGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchGesture:)];
170 | [self.scrollView addGestureRecognizer:_pinchPressGesture];
171 | }
172 |
173 | - (void)initCrossLine
174 | {
175 | WS(weakSelf);
176 | self.verticalView = [[KlineVerticalView alloc] init];
177 | self.verticalView.clipsToBounds = YES;
178 | [self.scrollView addSubview:self.verticalView];
179 | [self.verticalView mas_makeConstraints:^(MASConstraintMaker *make) {
180 | make.top.equalTo(weakSelf.scrollView.mas_top);
181 | make.width.equalTo(@(2));
182 | make.bottom.equalTo(weakSelf.candleChartView.mas_bottom).offset(-20);
183 | make.left.equalTo(@(0));
184 | }];
185 | self.leavView = [[KlineCurrentPriceView alloc] initWithUpdate:NO];
186 | self.leavView.clipsToBounds = YES;
187 | [self addSubview:self.leavView];
188 | [self.leavView mas_makeConstraints:^(MASConstraintMaker *make) {
189 | make.top.equalTo(@(0));
190 | make.left.equalTo(weakSelf);
191 | make.right.equalTo(weakSelf.candleChartView);
192 | make.height.equalTo(@(15));
193 | }];
194 |
195 | self.leavView.hidden = YES;
196 | self.verticalView.hidden = YES;
197 | }
198 |
199 | - (void)initdataLabel
200 | {
201 | _dataLable = [[UILabel alloc]init];
202 | _dataLable.font = [UIFont systemFontOfSize:10];
203 | _dataLable.textColor = [UIColor whiteColor];
204 | _dataLable.backgroundColor = [UIColor orangeColor];
205 | [self.candleChartView addSubview:self.dataLable];
206 | WS(weakSelf);
207 | [self.dataLable mas_makeConstraints:^(MASConstraintMaker *make) {
208 | make.bottom.equalTo(weakSelf.candleChartView.mas_bottom);
209 | make.width.mas_offset(priceWidth);
210 | make.height.mas_offset(15);
211 | make.left.equalTo(@0);
212 | }];
213 | self.dataLable.hidden = YES;
214 | }
215 |
216 | - (void)initCurrentPrice
217 | {
218 | WS(weakSelf);
219 | _currentPriceView = [[KlineCurrentPriceView alloc]initWithUpdate:YES];
220 | [self addSubview:self.currentPriceView];
221 | [self.currentPriceView mas_makeConstraints:^(MASConstraintMaker *make) {
222 | make.top.equalTo(@(0));
223 | make.left.equalTo(weakSelf);
224 | make.right.equalTo(weakSelf.candleChartView);
225 | make.height.equalTo(@(14));
226 | }];
227 | self.currentPriceView.hidden = YES;
228 | }
229 |
230 | - (void)longGesture:(UILongPressGestureRecognizer*)longPress
231 | {
232 | static CGFloat oldPositionX = 0;
233 | if(UIGestureRecognizerStateChanged == longPress.state || UIGestureRecognizerStateBegan == longPress.state)
234 | {
235 | CGPoint location = [longPress locationInView:self.candleChartView];
236 | if(ABS(oldPositionX - location.x) < (self.candleChartView.candleWidth + self.candleChartView.candleSpace)/2)
237 | {
238 | return;
239 | }
240 | self.scrollView.scrollEnabled = NO;
241 | oldPositionX = location.x;
242 | CGPoint point = [self.candleChartView getLongPressModelPostionWithXPostion:location.x];
243 | CGFloat xPositoin = point.x + (self.candleChartView.candleWidth)/2.f - self.candleChartView.candleSpace/2.f ;
244 | CGFloat yPositoin = point.y;
245 | [self.verticalView mas_updateConstraints:^(MASConstraintMaker *make) {
246 | make.left.equalTo(@(xPositoin));
247 | }];
248 | [self.leavView mas_updateConstraints:^(MASConstraintMaker *make) {
249 | make.top.mas_equalTo(yPositoin);
250 | }];
251 | [self.dataLable mas_updateConstraints:^(MASConstraintMaker *make) {
252 | make.left.equalTo(@(xPositoin - 35));
253 | }];
254 | self.verticalView.hidden = NO;
255 | self.leavView.hidden = NO;
256 | self.dataLable.hidden = NO;
257 | }
258 | if(longPress.state == UIGestureRecognizerStateEnded)
259 | {
260 | if(self.verticalView)
261 | {
262 | self.verticalView.hidden = YES;
263 | }
264 |
265 | if(self.leavView)
266 | {
267 | self.leavView.hidden = YES;
268 | }
269 | oldPositionX = 0;
270 | self.scrollView.scrollEnabled = YES;
271 | self.dataLable.hidden = YES;
272 | }
273 | }
274 |
275 | float oldScale = 0;
276 |
277 | - (void)pinchGesture:(UIPinchGestureRecognizer*)pinchPress
278 | {
279 | if (pinchPress.numberOfTouches < 2)
280 | {
281 | _candleChartView.kvoEnable = YES;
282 | _scrollView.scrollEnabled = YES;
283 | return;
284 | }
285 |
286 | switch (pinchPress.state) {
287 | case UIGestureRecognizerStateBegan:
288 | {
289 | _scrollView.scrollEnabled = NO;
290 | _candleChartView.kvoEnable = NO;
291 | oldScale = pinchPress.scale;
292 | }break;
293 | case UIGestureRecognizerStateEnded:
294 | {
295 | _scrollView.scrollEnabled = YES;
296 | _candleChartView.kvoEnable = YES;
297 | }break;
298 | default:
299 | break;
300 | }
301 | CGFloat minScale = 0.03;
302 | CGFloat diffScale = pinchPress.scale - oldScale;
303 |
304 | if (fabs(diffScale) > minScale)
305 | {
306 | CGFloat oldKlineWidth = self.candleChartView.candleWidth;
307 |
308 | self.candleChartView.candleWidth = (1 + diffScale) * oldKlineWidth;
309 |
310 | if (self.candleChartView.candleWidth > maxCandelWith) {
311 | self.candleChartView.candleWidth = maxCandelWith;
312 | }
313 | if (self.candleChartView.candleWidth < minCandelWith) {
314 | self.candleChartView.candleWidth = minCandelWith;
315 | }
316 | [_candleChartView updateWidth];
317 | CGPoint point1 = [pinchPress locationOfTouch:0 inView:self.scrollView];
318 | CGPoint point2 = [pinchPress locationOfTouch:1 inView:self.scrollView];
319 | CGFloat pinCenterX = (point1.x + point2.x) / 2;
320 | CGFloat scrollViewPinCenterX = pinCenterX;
321 | NSInteger pinCenterLeftCount = scrollViewPinCenterX / (_candleChartView.candleWidth + _candleChartView.candleSpace);
322 | pinCenterLeftCount = _candleChartView.currentStartIndex;
323 | CGFloat newPinCenterX = pinCenterLeftCount * _candleChartView.candleWidth + (pinCenterLeftCount) * _candleChartView.candleSpace;
324 | CGFloat newOffsetX = newPinCenterX;
325 | _scrollView.contentOffset = CGPointMake(newOffsetX > 0 ? newOffsetX : 0, 0);
326 | _candleChartView.contentOffset = _scrollView.contentOffset.x;
327 | [_candleChartView drawKLine];
328 | }
329 | }
330 |
331 |
332 | - (void)setDataArray:(NSMutableArray<__kindof KLineModel *> *)dataArray
333 | {
334 | _dataArray = dataArray;
335 | self.candleChartView.dataArray = dataArray;
336 | dispatch_async(dispatch_get_main_queue(), ^{
337 | [self.candleChartView reloadKline];
338 | });
339 | }
340 |
341 |
342 | - (void)refreshFSKlineView:(KLineModel *)model
343 | {
344 | [self.candleChartView refreshKLineView:model];
345 | [self.candleChartView layoutIfNeeded];
346 | [self setNeedsDisplay];
347 | }
348 |
349 | - (void)reloadPriceViewWithPriceArr:(NSArray *)priceArr
350 | {
351 | [self.priceView reloadPriceWithPriceArr:priceArr precision:2];
352 | }
353 |
354 | - (void)reloadPriceViewWithQuotaMaxValue:(double)maxValue MinValue:(double)minValue
355 | {
356 | [self.quotaPriceView reloadPriceWithPriceArr:@[@(maxValue),@(minValue)] precision:2];
357 | }
358 | - (void)showIndexLineView:(CGFloat)leftPostion startIndex:(NSInteger)index count:(NSInteger)count
359 | {
360 |
361 | }
362 |
363 | - (void)displayScreenleftPostion:(CGFloat)leftPostion startIndex:(NSInteger)index count:(NSInteger)count
364 | {
365 | [self showIndexLineView:leftPostion startIndex:index count:count];
366 | }
367 |
368 | - (void)longPressCandleViewWithIndex:(NSInteger)kLineModeIndex kLineModel:(KLineModel *)kLineModel
369 | {
370 | self.dataLable.text = kLineModel.timeStr;
371 | [self.leavView updateNewPrice:[NSString stringWithFormat:@"%.2lf",kLineModel.openPrice] backgroundColor:[UIColor orangeColor] precision:2];
372 | }
373 |
374 | - (void)refreshCurrentPrice:(KLineModel *)kLineModel candleModel:(KLineModel *)candleModel
375 | {
376 | CGFloat close = kLineModel.closesPoint.y;
377 | CGFloat y = close;
378 | [self.currentPriceView mas_updateConstraints:^(MASConstraintMaker *make) {
379 | make.top.mas_equalTo(y + topDistance);
380 | }];
381 | self.currentPriceView.hidden = NO;
382 | [self.currentPriceView updateNewPrice:[NSString stringWithFormat:@"%.2lf",candleModel.closePrice] backgroundColor:[UIColor orangeColor] precision:2];
383 | }
384 |
385 | - (void)displayLastModel:(KLineModel *)kLineModel
386 | {
387 |
388 | }
389 |
390 | - (void)displayMoreData
391 | {
392 | NSLog(@"1233333");
393 |
394 | }
395 |
396 | - (UIInterfaceOrientation)orientation
397 | {
398 | return [[UIApplication sharedApplication] statusBarOrientation];
399 | }
400 |
401 | - (UIScrollView *)scrollView
402 | {
403 | if (!_scrollView) {
404 | _scrollView = [[UIScrollView alloc]init];
405 | _scrollView.showsHorizontalScrollIndicator = NO;
406 | _scrollView.bounces = NO;
407 | _scrollView.layer.borderWidth = 1.0f;
408 | _scrollView.backgroundColor = [UIColor blackColor];
409 | _scrollView.layer.borderColor = [UIColor blackColor].CGColor;
410 | }
411 | return _scrollView;
412 | }
413 | - (AbuCandChartView *)candleChartView
414 | {
415 | if (!_candleChartView) {
416 | _candleChartView = [[AbuCandChartView alloc]init];
417 | _candleChartView.delegate = self;
418 | _candleChartView.candleSpace = 2;
419 | }
420 | return _candleChartView;
421 | }
422 |
423 | - (KlinePriceView *)priceView
424 | {
425 | if (!_priceView) {
426 | _priceView = [[KlinePriceView alloc] initWithFrame:CGRectMake(0,0,0,0) PriceArr:@[@"",@"",@"",@"",@"",@""]];
427 | _priceView.backgroundColor = [UIColor blackColor];
428 |
429 | }
430 | return _priceView;
431 | }
432 |
433 | - (KlinePriceView *)quotaPriceView
434 | {
435 | if (!_quotaPriceView) {
436 | _quotaPriceView = [[KlinePriceView alloc]initWithFrame:CGRectMake(0,0,0,0) PriceArr:@[@"",@""]];
437 | _quotaPriceView.backgroundColor = [UIColor blackColor];
438 | }
439 | return _quotaPriceView;
440 | }
441 |
442 | -(void)dealloc
443 | {
444 | [[NSNotificationCenter defaultCenter] removeObserver:self];
445 | }
446 |
447 | @end
448 |
--------------------------------------------------------------------------------
/AbuKlineView/KlineView/KLineView/KLineView/AbuCandChartView.m:
--------------------------------------------------------------------------------
1 | //
2 | // AbuCandChartView.m
3 | // AbuKlineView
4 | //
5 | // Created by 阿布 on 17/9/7.
6 | // Copyright © 2017年 阿布. All rights reserved.
7 | //
8 |
9 | #import "AbuCandChartView.h"
10 | #import "KlineQuotaColumnLayer.h"
11 | #import "KlineCandelLayer.h"
12 | #import "KlineTimeLayer.h"
13 | #import "KlineMALayer.h"
14 |
15 | #define MINDISPLAYCOUNT 6
16 | @interface AbuCandChartView()
17 | @property (nonatomic,strong) UIScrollView * scrollView;
18 | @property (nonatomic, strong) FBKVOController * KVOController;
19 | @property (nonatomic,assign) CGFloat leftPostion;
20 | @property (nonatomic,strong) NSMutableArray * currentDisplayArray;
21 | @property (nonatomic,assign) CGFloat previousOffsetX;
22 | @property (nonatomic,assign) CGFloat maxAssert;
23 | @property (nonatomic,assign) CGFloat minAssert;
24 | @property (nonatomic,assign) CGFloat heightPerpoint;
25 | @property (nonatomic, assign) BOOL isRefresh;
26 | @property (nonatomic, strong) KlineTimeLayer * timeLayer;
27 | @property (nonatomic, strong) KlineCandelLayer * candelLayer;
28 | @property (nonatomic, strong) KlineMALayer * ma5LineLayer;
29 | @property (nonatomic, strong) KlineMALayer * ma10LineLayer;
30 | @property (nonatomic, strong) KlineMALayer * ma20LineLayer;
31 | @property (nonatomic,assign) double quotaMinAssert;
32 | @property (nonatomic,assign) double quotaMaxAssert;
33 | @property (nonatomic,assign) CGFloat quotaHeightPerPoint;
34 | @property (nonatomic, strong) KlineQuotaColumnLayer * macdLayer;
35 | @property (nonatomic, strong) KlineMALayer * deaLayer;
36 | @property (nonatomic, strong) KlineMALayer * diffLayer;
37 | @property (nonatomic,strong) KlineMALayer * kLineLayer;
38 | @property (nonatomic,strong) KlineMALayer * dLineLayer;
39 | @property (nonatomic,strong) KlineMALayer * wrLineLayer;
40 | @property (nonatomic,assign) float chartSize;
41 | @property (nonatomic,assign) BOOL isShowSubView;
42 | @property (nonatomic, assign) CGFloat contentHeight;
43 | @end
44 | @implementation AbuCandChartView
45 |
46 | - (instancetype)init
47 | {
48 | self = [super init];
49 | if (self) {
50 | [self initConfig];
51 | [self calcuteCandleWidth];
52 | }
53 | return self;
54 | }
55 |
56 | -(void)initConfig
57 | {
58 | self.kvoEnable = YES;
59 | self.isRefresh = YES;
60 | self.chartSize = orignChartScale;
61 | self.isShowSubView = YES;
62 | }
63 |
64 | - (void)reloadKline
65 | {
66 | [self updateWidth];
67 | [self drawKLine];
68 | }
69 |
70 | #pragma mark KVO
71 |
72 | -(void)didMoveToSuperview
73 | {
74 | [super didMoveToSuperview];
75 | _scrollView = (UIScrollView*)self.superview;
76 | _scrollView.delegate = self;
77 | [self addListener];
78 | }
79 |
80 | - (void)addListener
81 | {
82 | FBKVOController *KVOController = [FBKVOController controllerWithObserver:self];
83 | self.KVOController = KVOController;
84 | WS(weakSelf);
85 | [self.KVOController observe:_scrollView keyPath:ContentOffSet options:NSKeyValueObservingOptionNew block:^(id _Nullable observer, id _Nonnull object, NSDictionary * _Nonnull change) {
86 | if (self.kvoEnable)
87 | {
88 | weakSelf.contentOffset = weakSelf.scrollView.contentOffset.x;
89 | weakSelf.previousOffsetX = weakSelf.scrollView.contentSize.width -weakSelf.scrollView.contentOffset.x;
90 | [weakSelf drawKLine];
91 | }
92 | }];
93 | }
94 | - (void)setKvoEnable:(BOOL)kvoEnable
95 | {
96 | _kvoEnable = kvoEnable;
97 | }
98 |
99 | - (NSInteger)currentStartIndex
100 | {
101 | CGFloat scrollViewOffsetX = self.leftPostion < 0 ? 0 : self.leftPostion;
102 |
103 | NSInteger leftArrCount = (scrollViewOffsetX) / (self.candleWidth+self.candleSpace);
104 |
105 | if (leftArrCount > self.dataArray.count)
106 | {
107 | _currentStartIndex = self.dataArray.count - 1;
108 | }
109 |
110 | else if (leftArrCount == 0)
111 | {
112 | _currentStartIndex = 0;
113 | }
114 |
115 | else
116 | {
117 | _currentStartIndex = leftArrCount ;
118 | }
119 | return _currentStartIndex;
120 | }
121 |
122 | - (CGFloat)leftPostion
123 | {
124 | CGFloat scrollViewOffsetX = _contentOffset < 0 ? 0 : _contentOffset;
125 | if (scrollViewOffsetX == 0) {
126 | scrollViewOffsetX = 10;
127 | }
128 | if (_contentOffset + self.scrollView.width >= self.scrollView.contentSize.width)
129 | {
130 | scrollViewOffsetX = self.scrollView.contentSize.width - self.scrollView.width;
131 | }
132 | return scrollViewOffsetX;
133 | }
134 |
135 | - (void)initCurrentDisplayModels
136 | {
137 | NSInteger needDrawKLineCount = self.scrollView.width / self.candleWidth;
138 | NSInteger currentStartIndex = self.currentStartIndex;
139 | NSInteger count = (currentStartIndex + needDrawKLineCount) >self.dataArray.count ? self.dataArray.count :currentStartIndex+needDrawKLineCount;
140 | [self.currentDisplayArray removeAllObjects];
141 |
142 | if (currentStartIndex < count)
143 | {
144 | for (NSInteger i = currentStartIndex; i < count ; i++)
145 | {
146 | KLineModel *model = self.dataArray[i];
147 | [self.currentDisplayArray addObject:model];
148 | }
149 | }
150 | }
151 |
152 | - (void)calcuteMaxAndMinValue
153 | {
154 | self.maxAssert = CGFLOAT_MIN;
155 | self.minAssert = CGFLOAT_MAX;
156 | NSInteger idx = 0;
157 | for (NSInteger i = idx; i < self.currentDisplayArray.count; i++)
158 | {
159 | KLineModel * entity = [self.currentDisplayArray objectAtIndex:i];
160 | self.minAssert = self.minAssert < entity.lowPrice ? self.minAssert : entity.lowPrice;
161 | self.maxAssert = self.maxAssert > entity.highPrice ? self.maxAssert : entity.highPrice;
162 |
163 | if (self.maxAssert - self.minAssert < 0.5)
164 | {
165 | self.maxAssert += 0.5;
166 | self.minAssert -= 0.5;
167 | }
168 | }
169 | CGFloat contentHeigh = self.scrollView.height / self.chartSize - topDistance - timeheight- topDistance;
170 | self.contentHeight = contentHeigh;
171 | self.heightPerpoint = contentHeigh / (self.maxAssert-self.minAssert);
172 | }
173 |
174 | - (void)drawMALineLayer
175 | {
176 | if (IsArrayNull(self.currentDisplayArray)) {
177 | return;
178 | }
179 | if (self.ma5LineLayer)
180 | {
181 | [self.ma5LineLayer removeFromSuperlayer];
182 | }
183 | self.ma5LineLayer = [[KlineMALayer alloc] initQuotaDataArr:self.currentDisplayArray candleWidth:self.candleWidth candleSpace:self.candleSpace startIndex:self.leftPostion maxValue:self.maxAssert heightPerpoint:self.heightPerpoint totalHeight:0 lineWidth:1 lineColor:[UIColor greenColor] wireType:MA5TYPE klineSubOrMain:Main];
184 | [self.layer addSublayer:self.ma5LineLayer];
185 |
186 |
187 | if (self.ma10LineLayer)
188 | {
189 | [self.ma10LineLayer removeFromSuperlayer];
190 | }
191 | self.ma10LineLayer = [[KlineMALayer alloc] initQuotaDataArr:self.currentDisplayArray candleWidth:self.candleWidth candleSpace:self.candleSpace startIndex:self.leftPostion maxValue:self.maxAssert heightPerpoint:self.heightPerpoint totalHeight:0 lineWidth:1 lineColor:[UIColor redColor] wireType:MA10TYPE klineSubOrMain:Main];
192 | [self.layer addSublayer:self.ma10LineLayer];
193 |
194 | if (self.ma20LineLayer)
195 | {
196 | [self.ma20LineLayer removeFromSuperlayer];
197 | }
198 | self.ma20LineLayer = [[KlineMALayer alloc] initQuotaDataArr:self.currentDisplayArray candleWidth:self.candleWidth candleSpace:self.candleSpace startIndex:self.leftPostion maxValue:self.maxAssert heightPerpoint:self.heightPerpoint totalHeight:0 lineWidth:1 lineColor:[UIColor blueColor] wireType:MA20TYPE klineSubOrMain:Main];
199 | [self.layer addSublayer:self.ma20LineLayer];
200 |
201 | }
202 |
203 |
204 |
205 | #pragma mark publicMethod
206 |
207 | - (CAShapeLayer*)getAxispLayer
208 | {
209 | CAShapeLayer *layer = [CAShapeLayer layer];
210 | layer.strokeColor = [UIColor colorWithHexString:@"#ededed"].CGColor;
211 | layer.fillColor = [[UIColor clearColor] CGColor];
212 | layer.contentsScale = [UIScreen mainScreen].scale;
213 | return layer;
214 | }
215 |
216 | - (void)calcuteCandleWidth
217 | {
218 | self.candleWidth = minCandelWith;
219 | }
220 |
221 | - (void)drawKLine
222 | {
223 | [self drawMainKline];
224 | if (self.delegate && [self.delegate respondsToSelector:@selector(reloadPriceViewWithPriceArr:)]) {
225 | NSArray * priceArray = [self calculatePrcieArrWhenScroll];
226 | [self.delegate reloadPriceViewWithPriceArr:priceArray];
227 | }
228 | [self drawPresetQuota:KlineSubKPITypeMACD];
229 | if (self.delegate && [self.delegate respondsToSelector:@selector(refreshCurrentPrice:candleModel:)]) {
230 | KLineModel * model = self.currentDisplayArray.lastObject;
231 | KLineModel *candelModel = self.currentDisplayArray.lastObject;
232 | [self.delegate refreshCurrentPrice:model candleModel:candelModel];
233 | }
234 | }
235 |
236 | - (void)drawMainKline
237 | {
238 | [self drawCandelLayer];
239 | [self drawMALineLayer];
240 | [self drawTimeLayer];
241 | }
242 |
243 | - (void)drawCandelLayer
244 | {
245 |
246 | [self initCurrentDisplayModels];
247 | [self calcuteMaxAndMinValue];
248 | if (self.delegate && [self.delegate respondsToSelector: @selector(displayScreenleftPostion:startIndex:count:)])
249 | {
250 | [_delegate displayScreenleftPostion:self.leftPostion startIndex:self.currentStartIndex count:self.currentDisplayArray.count];
251 | }
252 | if (self.delegate && [self.delegate respondsToSelector:@selector(displayLastModel:)])
253 | {
254 | KLineModel *lastModel = self.currentDisplayArray.lastObject;
255 | [_delegate displayLastModel:lastModel];
256 | }
257 | if (self.candelLayer)
258 | {
259 | [self.candelLayer removeFromSuperlayer];
260 | }
261 | self.candelLayer = [[KlineCandelLayer alloc] initQuotaDataArr:self.currentDisplayArray candleWidth:self.candleWidth candleSpace:self.candleSpace startIndex:self.leftPostion maxValue:self.maxAssert heightPerpoint:self.heightPerpoint scrollViewContentWidth:self.scrollView.contentSize.width];
262 | [self.layer addSublayer:self.candelLayer];
263 | }
264 |
265 | - (void)drawTimeLayer
266 | {
267 | if (self.timeLayer)
268 | {
269 | [self.timeLayer removeFromSuperlayer];
270 | self.timeLayer = nil;
271 | }
272 | self.timeLayer = [[KlineTimeLayer alloc] initQuotaDataArr:self.currentDisplayArray candleWidth:self.candleWidth height:self.scrollView.height / self.chartSize timeHight:timeheight bottomMargin:0 lineWidth:0];
273 | [self.layer addSublayer:self.timeLayer];
274 | }
275 |
276 | - (NSArray *)calculatePrcieArrWhenScroll
277 | {
278 | NSMutableArray *priceArr = [NSMutableArray array];
279 |
280 | for (int i = 5; i>=0; i--) {
281 |
282 | if (i==5) {
283 |
284 | [priceArr addObject:@(self.maxAssert)];
285 | continue;
286 | }
287 | if (i==0) {
288 |
289 | [priceArr addObject:@(self.minAssert)];
290 | continue;
291 | }
292 | [priceArr addObject:@((self.minAssert + ((self.contentHeight/5)*i/self.heightPerpoint)))];
293 | }
294 | return [priceArr copy];
295 | }
296 |
297 | - (void)updateWidth
298 | {
299 | CGFloat klineWidth = self.dataArray.count * (self.candleWidth + self.candleSpace) + 5;
300 |
301 | if(klineWidth < self.scrollView.width)
302 | {
303 | klineWidth = self.scrollView.width;
304 | }
305 |
306 | [self mas_updateConstraints:^(MASConstraintMaker *make) {
307 | make.width.equalTo(@(klineWidth));
308 | }];
309 |
310 | self.scrollView.contentSize = CGSizeMake(klineWidth,0);
311 | if (self.isRefresh) {
312 | self.scrollView.contentOffset = CGPointMake(klineWidth - self.scrollView.width, 0);
313 | }
314 |
315 | }
316 |
317 |
318 |
319 | -(CGPoint)getLongPressModelPostionWithXPostion:(CGFloat)xPostion
320 | {
321 | CGFloat localPostion = xPostion;
322 | NSInteger startIndex = (NSInteger)((localPostion - self.leftPostion) / (self.candleSpace + self.candleWidth));
323 | NSInteger arrCount = self.currentDisplayArray.count;
324 | for (NSInteger index = startIndex > 0 ? startIndex - 1 : 0; index < arrCount; ++index) {
325 | KLineModel *kLinePositionModel = self.currentDisplayArray[index];
326 | CGFloat minX = kLinePositionModel.highestPoint.x - (self.candleSpace + self.candleWidth/2);
327 | CGFloat maxX = kLinePositionModel.highestPoint.x + (self.candleSpace + self.candleWidth/2);
328 | if(localPostion > minX && localPostion < maxX)
329 | {
330 | if(self.delegate && [self.delegate respondsToSelector:@selector(longPressCandleViewWithIndex:kLineModel:)])
331 | {
332 | [self.delegate longPressCandleViewWithIndex:index kLineModel:self.currentDisplayArray[index]];
333 | }
334 | return CGPointMake(kLinePositionModel.highestPoint.x, kLinePositionModel.opensPoint.y);
335 | }
336 | }
337 |
338 | KLineModel *lastPositionModel = self.currentDisplayArray.lastObject;
339 |
340 | if (localPostion >= lastPositionModel.closesPoint.x)
341 | {
342 | return CGPointMake(lastPositionModel.highestPoint.x, lastPositionModel.opensPoint.y);
343 | }
344 | KLineModel *firstPositionModel = self.currentDisplayArray.firstObject;
345 | if (firstPositionModel.closesPoint.x >= localPostion)
346 | {
347 | return CGPointMake(firstPositionModel.highestPoint.x, firstPositionModel.opensPoint.y);
348 | }
349 | return CGPointZero;
350 | }
351 |
352 | - (void)drawPresetQuota:(KlineSubKPIType)presetQuotaName;
353 | {
354 | if (self.isShowSubView) {
355 | [self calcuteQuotaMaxAssertAndMinAssert:presetQuotaName];
356 | switch (presetQuotaName) {
357 | case KlineSubKPITypeMACD:
358 | [self drawPresetMACD];
359 | break;
360 | case KlineSubKPITypeKD:
361 | [self drawPresetKD];
362 | break;
363 | case KlineSubKPITypeW_R:
364 | [self drawPresetWR];
365 | break;
366 | default:
367 | break;
368 | }
369 | }
370 | else
371 | {
372 | [self removeSubSubLayers];
373 | }
374 |
375 | }
376 |
377 | - (void)drawPresetMACD
378 | {
379 | if (self.macdLayer) {
380 | [self.macdLayer removeFromSuperlayer];
381 | }
382 | self.macdLayer = [[KlineQuotaColumnLayer alloc] initQuotaDataArr:self.currentDisplayArray candleWidth:self.candleWidth candleSpace:self.candleSpace startIndex:self.leftPostion maxValue:self.quotaMaxAssert heightPerpoint:self.quotaHeightPerPoint qutoaHeight:self.scrollView.height * orignIndicatorOrignY];
383 | [self.layer addSublayer:self.macdLayer];
384 | if (self.diffLayer) {
385 | [self.diffLayer removeFromSuperlayer];
386 | }
387 | self.diffLayer = [[KlineMALayer alloc] initQuotaDataArr:self.currentDisplayArray candleWidth:self.candleWidth candleSpace:self.candleSpace startIndex:self.leftPostion maxValue:self.quotaMaxAssert heightPerpoint:self.quotaHeightPerPoint totalHeight:self.scrollView.height *orignIndicatorOrignY lineWidth:1 lineColor:[UIColor yellowColor] wireType:MACDDIFF klineSubOrMain:Sub];
388 | [self.layer addSublayer:self.diffLayer];
389 | if (self.deaLayer) {
390 | [self.deaLayer removeFromSuperlayer];
391 | }
392 | self.deaLayer = [[KlineMALayer alloc] initQuotaDataArr:self.currentDisplayArray candleWidth:self.candleWidth candleSpace:self.candleSpace startIndex:self.leftPostion maxValue:self.quotaMaxAssert heightPerpoint:self.quotaHeightPerPoint totalHeight:self.scrollView.height *orignIndicatorOrignY lineWidth:1 lineColor:[UIColor purpleColor] wireType:MACDDEA klineSubOrMain:Sub];
393 | [self.layer addSublayer:self.deaLayer];
394 | }
395 | - (void)drawPresetKD
396 | {
397 | if (self.kLineLayer) {
398 | [self.kLineLayer removeFromSuperlayer];
399 | }
400 | self.kLineLayer = [[KlineMALayer alloc] initQuotaDataArr:self.currentDisplayArray candleWidth:self.candleWidth candleSpace:self.candleSpace startIndex:self.leftPostion maxValue:self.quotaMaxAssert heightPerpoint:self.quotaHeightPerPoint totalHeight:self.scrollView.height *orignIndicatorOrignY lineWidth:1 lineColor:[UIColor yellowColor] wireType:KDJ_K klineSubOrMain:Sub];
401 | [self.layer addSublayer:self.kLineLayer];
402 | if (self.dLineLayer) {
403 | [self.dLineLayer removeFromSuperlayer];
404 | }
405 | self.dLineLayer = [[KlineMALayer alloc] initQuotaDataArr:self.currentDisplayArray candleWidth:self.candleWidth candleSpace:self.candleSpace startIndex:self.leftPostion maxValue:self.quotaMaxAssert heightPerpoint:self.quotaHeightPerPoint totalHeight:self.scrollView.height *orignIndicatorOrignY lineWidth:1 lineColor:[UIColor orangeColor] wireType:KDJ_D klineSubOrMain:Sub];
406 | [self.layer addSublayer:self.dLineLayer];
407 | }
408 | - (void)drawPresetWR
409 | {
410 | if (self.wrLineLayer) {
411 | [self.wrLineLayer removeFromSuperlayer];
412 | }
413 | self.wrLineLayer = [[KlineMALayer alloc] initQuotaDataArr:self.currentDisplayArray candleWidth:self.candleWidth candleSpace:self.candleSpace startIndex:self.leftPostion maxValue:self.quotaMaxAssert heightPerpoint:self.quotaHeightPerPoint totalHeight:self.scrollView.height *orignIndicatorOrignY lineWidth:1 lineColor:[UIColor orangeColor] wireType:KLINE_WR klineSubOrMain:Sub];
414 | [self.layer addSublayer:self.wrLineLayer];
415 | }
416 | - (void)calcuteQuotaMaxAssertAndMinAssert:(KlineSubKPIType)subType
417 | {
418 | NSDictionary *resultDic;
419 | CGFloat contentHeigh = self.scrollView.height * orignIndicatorOrignY - midDistance;
420 | if (subType == KlineSubKPITypeMACD) {
421 | NSMutableArray * DEAArray = [NSMutableArray array];
422 | NSMutableArray * DIFArray = [NSMutableArray array];
423 | NSMutableArray * MACDArray = [NSMutableArray array];
424 | for (NSInteger i = 0;i